I am trying to use a Developer Authenticated Provider to login to my android app basing it loosely off of this demo: https://github.com/awslabs/aws-sdk-android-samples/tree/master/CognitoSyncDemo. I successfully logged in through our own backend got the idToken and subsequently got session credentials to access our AWS database. I then used those credentials to make a POST to the db.
But this only worked once, now I cannot get through again, without having changed any code. I am also using a generated SDK through http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-generate-sdk.html. I'm not sure if this is causing any errors.
Here is my DeveloperAuthenticationProvider:
public class AuthenticationProvider extends
AWSAbstractCognitoDeveloperIdentityProvider {
private static final String TAG = AuthenticationProvider.class.getSimpleName();
private static SocializeClient mSocializeClient;
private static final String developerProvider = Constants.AWS_PROVIDER_NAME;
private static final String cognitoSampleDeveloperAuthenticationAppEndpoint = UrlEndpoints.URL_DOMAIN;
public AuthenticationProvider(Context context, String accountId, String identityPoolId, Regions region) {
super(accountId, identityPoolId, region);
/*
* Initialize the client using which you will communicate with your
* backend for user authentication.
*/
AWSCredentialsProvider awsCredentialsProvider = new CognitoCachingCredentialsProvider(
context,
this,
region
);
ApiClientFactory factory = new ApiClientFactory()
.endpoint(cognitoSampleDeveloperAuthenticationAppEndpoint)
.credentialsProvider(awsCredentialsProvider);
mSocializeClient = factory.build(SocializeClient.class);
}
/*Only refreshes the login info, when it has expired*/
/*
* (non-Javadoc)
* #see com.amazonaws.auth.AWSCognitoIdentityProvider#refresh() In refresh
* method, you will have two flows:
*/
/*
* 1. When the app user uses developer authentication. In this case, make
* the call to your developer backend, from where call the
* GetOpenIdTokenForDeveloperIdentity API of Amazon Cognito service. Be sure to call update(), so as to
* set the identity id and the token received.
*/
/*
* 2.When the app user is not using the developer authentication, just call
* the refresh method of the AWSAbstractCognitoDeveloperIdentityProvider
* class which actually calls GetId and GetOpenIDToken API of Amazon
* Cognito.
*/
#Override
public String refresh() {
Log.i(TAG, "refresh");
// If there is a key with developer provider name in the logins map, it
// means the app user has used developer credentials
if (!loginsMap.isEmpty()
&& loginsMap.containsKey(developerProvider)) {
Log.i(TAG, "contains provider");
} else {
Log.i(TAG, "does not contain developer provider");
Map<String, String> logins = new HashMap<>();
logins.put(developerProvider, UserSingleton.imei);
setLogins(logins);
}
// TODO:: Temp code to login. Once available, need to add code to GetToken from SocializeClient
Login login = new Login();
login.setImei(UserSingleton.imei);
login.setPassword(UserSingleton.password);
LoginReponse loginReponse = mSocializeClient.socializeAuthLoginPost(login);
Log.i(TAG, "login response: " + loginReponse.getIdentityId() + " - token: " + loginReponse.getToken());
update(loginReponse.getIdentityId(), loginReponse.getToken());
Log.i(TAG, "updated");
return loginReponse.getToken();
}
/*
* (non-Javadoc)
* #see com.amazonaws.auth.AWSBasicCognitoIdentityProvider#getIdentityId()
*/
/*
* This method again has two flows as mentioned above depending on whether
* the app user is using developer authentication or not. When using
* developer authentication system, the identityId should be retrieved from
* the developer backend. In the other case the identityId will be retrieved
* using the getIdentityId() method which in turn calls Cognito GetId and
* GetOpenIdToken APIs.
*/
#Override
public String getIdentityId() {
Log.i(TAG, "getIdentityId");
identityId = CognitoSyncClientManager.credentialsProvider.getCachedIdentityId();
if (identityId == null) {
Log.i(TAG, "identityId is null");
if (!loginsMap.isEmpty()
&& loginsMap.containsKey(developerProvider)) {
Log.i(TAG, "grabbing identityId using logins map");
// TODO:: Temp code to login. Once available, need to add code to GetToken from SocializeClient
Login login = new Login();
login.setImei(loginsMap.get(developerProvider));
login.setPassword(UserSingleton.password);
LoginReponse loginReponse = mSocializeClient.socializeAuthLoginPost(login);
Log.i(TAG, "login response: " + loginReponse.getIdentityId() + " - token: " + loginReponse.getToken());
update(loginReponse.getIdentityId(), loginReponse.getToken());
return loginReponse.getIdentityId();
} else {
return super.getIdentityId();
}
} else {
return identityId;
}
}
/*
* (non-Javadoc)
* #see
* com.amazonaws.auth.AWSAbstractCognitoIdentityProvider#getProviderName()
* Return the developer provider name which you chose while setting up the
* identity pool in the Amazon Cognito Console
*/
#Override
public String getProviderName() {
return developerProvider;
}
/**
* This function validates the user credentials against the sample Cognito
* developer authentication application. After that it stores the key and
* token received from sample Cognito developer authentication application
* for all further communication with the application.
*
* #param imei
* #param password
*/
public void login(String imei, String password, Context context) {
Log.i(TAG, "login");
Login login = new Login();
login.setImei(imei);
login.setPassword(password);
new AuthenticationTask(context).execute(login);
}
public void publishProfile(Context context, Profile profile){
Log.i(TAG, "publishProfile");
ProfileKey profileKey = new ProfileKey();
profileKey.setUserID(identityId);
profile.setKey(profileKey);
new UploadProfileTask(context).execute(profile);
}
protected static SocializeClient getSocializeClientInstance() {
if (mSocializeClient == null) {
throw new IllegalStateException(
"Dev Auth Client not initialized yet");
}
return mSocializeClient;
}
}
Here is my AuthenticationTask as well where I attempt to login, then grab credentials to access the AWS database:
public class AuthenticationTask extends
AsyncTask<Login, Void, Void> {
private static final String TAG = AuthenticationTask.class.getSimpleName();
// The user name or the developer user identifier you will pass to the
// Amazon Cognito in the GetOpenIdTokenForDeveloperIdentity API
private String mImei;
private String mPassword;
private GetCredentialsForIdentityResult credentialsForIdentityResult;
private boolean isSuccessful;
private final Context context;
public AuthenticationTask(Context context) {
this.context = context;
}
#Override
protected Void doInBackground(Login... params) {
Log.i(TAG, "doInBackground get refreshing threshold: " + CognitoCachingCredentialsProvider.DEFAULT_THRESHOLD_SECONDS);
mImei = params[0].getImei();
mPassword = params[0].getPassword();
Login login = params[0];
// if(mPassword == null){
// Log.i(TAG, "register");
// mPassword = Utils.generateRandomString();
// final Register register = new Register();
// register.setImei(mImei);
// register.setPassword(mPassword);
// login.setPassword(mPassword);
// RegisterResponse registerResponse = AuthenticationProvider.getSocializeClientInstance().socializeAuthRegisterPost(register);
// Log.i(TAG, "registerResponse: " + registerResponse.getCreated());
UserSingleton.password = mPassword;
UserSingleton.getInstance().saveRegistrationInfo();
Log.i(TAG, "imei: " + mImei);
// }
Log.i(TAG, "calling login post");
LoginReponse loginReponse = AuthenticationProvider.getSocializeClientInstance().socializeAuthLoginPost(login);
Log.i(TAG, "login response: " + loginReponse.getIdentityId() + " - token: " + loginReponse.getToken());
// Set up the loginsMap to send with the credentials request
Map<String, String> loginsMap = new HashMap<>();
loginsMap.put(CognitoSyncClientManager.developerIdentityProvider.getProviderName(), loginReponse.getToken());
// get AWS credentials to access DB
GetCredentialsForIdentityRequest credentialsForIdentityRequest = new GetCredentialsForIdentityRequest();
credentialsForIdentityRequest.setIdentityId(loginReponse.getIdentityId());
credentialsForIdentityRequest.setLogins(loginsMap);
Log.i(TAG, "credentials request: " + credentialsForIdentityRequest.getIdentityId() + credentialsForIdentityRequest.getLogins());
AmazonCognitoIdentityClient cognitoIdentityClient = new AmazonCognitoIdentityClient(CognitoSyncClientManager.credentialsProvider);
credentialsForIdentityResult = cognitoIdentityClient
.getCredentialsForIdentity(credentialsForIdentityRequest);
isSuccessful = credentialsForIdentityResult != null;
return null;
}
#Override
protected void onPostExecute(Void result) {
if (isSuccessful) {
Log.i(TAG, "accessKeyId: " + credentialsForIdentityResult.getCredentials().getAccessKeyId()
+ "\nsecretKey: " + credentialsForIdentityResult.getCredentials().getSecretKey()
+ "\nsessionToken: " + credentialsForIdentityResult.getCredentials().getSessionToken());
CognitoSyncClientManager
.addLogins(
((AuthenticationProvider) CognitoSyncClientManager.credentialsProvider
.getIdentityProvider()).getProviderName(),
mImei);
} else {
Log.i(TAG, "login error: " + result);
}
}
}
In my refresh call I am just relogging in. I'm not sure if that is correct.
The biggest issue now is upon startup when I attempt to login using, mSocializeClient.socializeAuthLoginPost(login) it seems to call refresh every time, before it even logs in. Refresh then attempts to login again and it keeps calling itself endlessly.
Any help/explanations would be greatly appreciated.
The way the dev auth sample works is as follows:
The DeveloperAuthenticationTask.login() is supposed to login to the server and get a session key.
It sets up the logins map and calls DeveloperAuthenticationProvider.refresh()
Refresh exchanges the session key with the server for a valid cognito token and identity id and calls update with the token and identity id.
In your case, you don't have this session key, just username and password. So you don't need the AuthenticationTask. All you need is:
a login() in your AuthenticationProvider, that puts the username/password in a secure location, sets up the login map and calls refresh (it shouldn't actually attempt to login to your service).
In refresh() you retrieve the username/pass from the secure location, call your service and then call update with the token and identity id returned from your service.
Can you simplify your code to this flow?
Related
I am creating an Android application which uses Azure AD for authentication. I need to access some WebAPIs on the Azure server which is secured using Azure AD authentication. I am able to generate the token. When I try to access the WebAPI it gives an 401 unauthorized error.
private void azureADLogin(){
mAuthContext = new AuthenticationContext(getApplicationContext(), AUTHORITY, false);
/* Instantiate handler which can invoke interactive sign-in to get the Resource
* sIntSignInInvoked ensures interactive sign-in is invoked one at a time */
mAcquireTokenHandler = new Handler(Looper.getMainLooper()){
#Override
public void handleMessage(Message msg) {
if( sIntSignInInvoked.compareAndSet(false, true)) {
if (msg.what == MSG_INTERACTIVE_SIGN_IN_PROMPT_AUTO){
mAuthContext.acquireToken(MainActivity.this, RESOURCE_ID, CLIENT_ID, REDIRECT_URI, PromptBehavior.Auto, getAuthInteractiveCallback());
}else if(msg.what == MSG_INTERACTIVE_SIGN_IN_PROMPT_ALWAYS){
mAuthContext.acquireToken(MainActivity.this, RESOURCE_ID, CLIENT_ID, REDIRECT_URI, PromptBehavior.Always, getAuthInteractiveCallback());
}
}
}
};
/* ADAL Logging callback setup */
Logger.getInstance().setExternalLogger(new Logger.ILogger() {
#Override
public void Log(String tag, String message, String additionalMessage, Logger.LogLevel level, ADALError errorCode) {
// You can filter the logs depending on level or errorcode.
Log.d(Constants.TAG, message + " " + additionalMessage);
}
});
/*Attempt an acquireTokenSilent call to see if we're signed in*/
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
String userId = preferences.getString(USER_ID, "");
if(!TextUtils.isEmpty(userId)){
mAuthContext.acquireTokenSilentAsync(RESOURCE_ID, CLIENT_ID, userId, getAuthSilentCallback());
}else {
mAcquireTokenHandler.sendEmptyMessage(MSG_INTERACTIVE_SIGN_IN_PROMPT_ALWAYS);
}
} // end of azure AD Login
I recently began working with Google Cloud Messaging for push notifications. I have an app that I have not released a signed apk for (information provided in case there is some detection of dev builds) and have not reinstalled the app in any way shape or form.
My app requests a registration ID, I store it manually while the server side is being worked on, and test with a small bit of code on the server that is set up to send push notifications. It works for the bulk of the day but the following morning I get a response "{ error: 'NotRegistered' }".
I have taken no actions to unregister the device and the app version has not changed.
[edit] Added relevant bits from Android Manifest
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- Stuff for push notifications -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<permission android:name="com.my.package.permission.C2D_MESSAGE"
android:protectionLevel="signature"/>
<uses-permission android:name="com.my.package.permission.C2D_MESSAGE" />
<!-- end push notifications stuff -->
public void onResume(){
super.onResume();
/**
* Check for Google Play Services APK
*/
if(myApp.checkPlayServices(this)){
gcm = GoogleCloudMessaging.getInstance(this);
regid = getRegistrationId(getApplicationContext());
if( regid == null || regid.isEmpty() || (myApp.getSP().getInt(Constants.PROPERTY_APP_VERSION,-1) <= getAppVersion(this)) ){
registerInBackground();
} else {
L.i("Using GCM ID:" + regid);
}
} else {
L.i("No valid Google Play Services APK found.");
}
IntentFilter intentFilter = new IntentFilter("com.google.android.c2dm.intent.RECEIVE");
gcmReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
String[] params = {extras.getString("imgUrl"), gcm.getMessageType(intent), extras.toString()};
new GCMReceiverTask().execute(params);
}
};
this.registerReceiver(gcmReceiver,intentFilter);
}
/**
* Stuff pertaining to push notifications
*/
String SENDER_ID = null;
String regid = null;
GoogleCloudMessaging gcm;
/**
* Gets the current registration ID for application on GCM service.
* <p>
* If result is empty, the app needs to register.
*
* #return registration ID, or empty string if there is no existing
* registration ID.
*/
private String getRegistrationId(Context context) {
final SharedPreferences prefs = myApp.getSP();
String registrationId = prefs.getString(Constants.PROPERTY_REG_ID, "");
if (registrationId.isEmpty()) {
L.i("Registration not found.");
return "";
}
// Check if app was updated; if so, it must clear the registration ID
// since the existing registration ID is not guaranteed to work with
// the new app version.
int registeredVersion = prefs.getInt(Constants.PROPERTY_APP_VERSION, Integer.MIN_VALUE);
int currentVersion = getAppVersion(context);
if (registeredVersion != currentVersion) {
L.i("App version changed.");
return "";
}
return registrationId;
}
/**
* #return Application's version code from the {#code PackageManager}.
*/
private static int getAppVersion(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionCode;
} catch (PackageManager.NameNotFoundException e) {
// should never happen
throw new RuntimeException("Could not get package name: " + e);
}
}
/**
* Registers the application with GCM servers asynchronously.
* <p>
* Stores the registration ID and app versionCode in the application's
* shared preferences.
*/
private void registerInBackground() {
new GCMRegistrationTask().execute(null, null, null);
}
/**
* Sends the registration ID to your server over HTTP, so it can use GCM/HTTP
* or CCS to send messages to your app. Not needed for this demo since the
* device sends upstream messages to a server that echoes back the message
* using the 'from' address in the message.
*/
private void sendRegistrationIdToBackend() {
// Your implementation here.
L.i("WOULD SEND REGISTRATION TO SERVER... " + regid);
}
/**
* Stores the registration ID and app versionCode in the application's
* {#code SharedPreferences}.
*
* #param regId registration ID
*/
private void storeRegistrationId(String regId) {
final SharedPreferences prefs = myApp.getSP();
int appVersion = getAppVersion(this);
L.i("Saving regId on app version " + appVersion);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(Constants.PROPERTY_REG_ID, regId);
editor.putInt(Constants.PROPERTY_APP_VERSION, appVersion);
editor.commit();
}
/**
* Unregisters the application with GCM servers asynchronously.
* <p>
* Removes the registration ID and app versionCode from the application's
* shared preferences.
*/
private void unRegisterInBackground() {
new GCMRegistrationTask(true).execute(null, null, null);
}
private class GCMReceiverTask extends AsyncTask<String, Void, String>{
#Override
protected String doInBackground(String... params) {
// Expect params[0] to be image URL, params[1] to be messageType
String imageUrl = params[0];
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(Main.this);
// The getMessageType() intent parameter must be the intent you received
// in your BroadcastReceiver.
String messageType = params[1];
// Stringified extras as last param
String extrasString = params[params.length - 1];
/*
* Filter messages based on message type. Since it is likely that GCM
* will be extended in the future with new message types, just ignore
* any message types you're not interested in, or that you don't
* recognize.
*/
if (GoogleCloudMessaging.
MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
L.e("Send error: " + extrasString);
} else if (GoogleCloudMessaging.
MESSAGE_TYPE_DELETED.equals(messageType)) {
L.i("Deleted messages on server: " +
extrasString);
// If it's a regular GCM message, do some work.
} else if (GoogleCloudMessaging.
MESSAGE_TYPE_MESSAGE.equals(messageType)) {
// retrieve image
try {
L.i("Got image URL: " + imageUrl);
String[] parts = imageUrl.split("/");
String fileName = parts[parts.length - 1];
if (imageUrl.isEmpty()) {
throw new Exception("No Image URL supplied.");
}
ServerCall sc = new ServerCall(imageUrl, ServerCall.POST);
String path = Environment.getExternalStorageDirectory() + File.separator + getPackageName().toString() + File.separator + "user_images";
sc.saveByteArrayToLocalFile(path, fileName);
} catch (Exception e) {
L.e("ERROR writing image to storage: " + Log.getStackTraceString(e));
}
// Post notification of received message.
L.i("Received: " + extrasString);
}
return null;
}
#Override
protected void onPostExecute(String msg){
Button proceed = (Button)findViewById(R.id.button4);
if( proceed != null ){
proceed.setEnabled(true);
}
}
}
private class GCMRegistrationTask extends AsyncTask<Void, Void, String> {
private boolean unregistering = false;
GCMRegistrationTask() {
this(false);
}
GCMRegistrationTask(boolean unregister) {
super();
this.unregistering = unregister;
}
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(getApplicationContext());
}
if( unregistering ) {
gcm.unregister();
myApp.getSP()
.edit()
.remove(Constants.PROPERTY_REG_ID)
.commit();
} else {
SENDER_ID = myApp.getSP().getString(Constants.GCM_SENDER_ID,null);
if( SENDER_ID != null ) {
regid = gcm.register(SENDER_ID);
msg = "Device registered, registration ID=" + regid;
// You should send the registration ID to your server over HTTP,
// so it can use GCM/HTTP or CCS to send messages to your app.
// The request to your server should be authenticated if your app
// is using accounts.
sendRegistrationIdToBackend();
// For this demo: we don't need to send it because the device
// will send upstream messages to a server that echo back the
// message using the 'from' address in the message.
// Persist the registration ID - no need to register again.
storeRegistrationId(regid);
} else {
L.e("SHOULD NOT GET HERE, GCM_SENDER_ID SHOULD NOT BE NULL! " + myApp.getSP().getString(Constants.GCM_SENDER_ID,"[[EMPTY]]"));
}
}
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
// If there is an error, don't just keep trying to register.
// Require the user to click a button again, or perform
// exponential back-off.
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
// handle postExecute - Nothing to do?
}
}
This is intentional.
Registration IDs will expire after some time. Client should detect that and request another ID.
http://developer.android.com/google/gcm/client.html
As stated above, an Android app must register with GCM servers and get a registration ID before it can receive messages. A given registration ID is not guaranteed to last indefinitely, so the first thing your app should always do is check to make sure it has a valid registration ID (as shown in the code snippets above).
I have read this whole article for the authentication using OAuth2.0.
But I didn't find a suitable method to do this on an android application. Please suggest a method to get the access token so that I can build a Gmail service object and access the inbox or any other method.
This is the example given by them in this link:
GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
Plus plus = new Plus.builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), credential)
.setApplicationName("Google-PlusSample/1.0")
.build();
Invoke the below method to get the token and the google account used in mobile. This method first retrieves the google account setup in your mobile and later retrieves the token.
You can save the token and account name using preferences for later use so that you dont have to retrieve the token each time.
private void chooseAccount() {
Intent intent = AccountPicker.newChooseAccountIntent(null, null,
new String[]{"com.google"}, false, null, null, null, null);
startActivityForResult(intent, 9009);
}
After the account is retrieved the below method is called,
public static final String MAIL_GOOGLE_COM = "https://mail.google.com";
public static final String GMAIL_COMPOSE = "https://www.googleapis.com/auth/gmail.compose";
public static final String GMAIL_MODIFY = "https://www.googleapis.com/auth/gmail.modify";
private static final String SCOPE = "oauth2:" + GMAIL_COMPOSE + " " + GMAIL_MODIFY + " " + MAIL_GOOGLE_COM;
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
//accountname - google account in your mobile is retrieved
//now use the google account to retrieve the token
new GetToken(getActivity().getApplicationContext(), SCOPE, accountName).execute();
showErrorDialog(exception);
}
} else if (requestCode == Activity.RESULT_CANCELED) {
Toast.makeText(getActivity(), "Cancelled!!!", Toast.LENGTH_SHORT).show();
}
}
Below class is used to get the token.
private class GetToken extends AsyncTask<Void, Void, Void> {
Context context;
String mScope, mEmail, token;
GetToken(Context context, String scope, String email) {
this.context = context;
this.mScope = scope;
this.mEmail = email;
}
#Override
protected Void doInBackground(Void... params) {
try {
token = GoogleAuthUtil.getToken(context, mEmail, mScope);
//save the token using preference for later use or do any good stuff using token here
Log.v("ranjapp", "Token is " + token);
} catch (UserRecoverableAuthException e) {
handleException(e);
} catch (GoogleAuthException ex) {
handleException(ex);
} catch (Exception e) {
//display a error dialog
}
return null;
}
void handleException(final Exception e) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if (e instanceof UserRecoverableAuthException) {
Intent intent = ((UserRecoverableAuthException) e).getIntent();
startActivityForResult(intent, 10098);
} else if (e instanceof GooglePlayServicesAvailabilityException) {
int statusCode = ((GooglePlayServicesAvailabilityException) e)
.getConnectionStatusCode();
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(statusCode, getActivity(), 10099);
dialog.show();
}
}
});
}
}
You have to register your app in google play console to get the token successfully. Also ensure you have play services setup in your app.
To register your Android app with Google Cloud Console:
Visit Google Cloud Console.
If you have an existing project to which you're adding an Android app, select the project. Otherwise, click Create project at the top, enter your project name and ID, then click Create.
Note: The name you provide for the project is the name that appears to users in the Google Settings app in the list of Connected apps.
In the left-side navigation, select APIs & auth.
Enable the API you'd like to use by setting the Status to ON.
In the left-side navigation, select Credentials.
Click Create new client ID or Create new key as appropriate for your app.
Complete the form that appears by filling in your Android app details.
To get the SHA1 fingerprint for your app, run the following command in a terminal:
keytool -exportcert -alias <keystore_alias> -keystore <keystore_path> -list -v
For example, you're using a debug-key with Eclipse, then the command looks like this:
keytool -exportcert -alias androiddebugkey-keystore ~/.android/debug.keystore -list -v
Then the keystore password is "android".
Click Create.
For more information: https://developer.android.com/google/auth/http-auth.html
This library might make it easier for you:
https://github.com/Hafiz-Waleed-Hussain/EasySocial
Additionally you can check the source for the actual implementation.
Can we implement Paypal with a card payment. e.g. Somebody doesn't have paypal account so he/she can pay using debit or credit card. Is there any way to implement paypal with card.
Please help.
Hi I know I am very late to answer this question but surely folks implementing Paypal in their app will get benefit from this!
Android SDK for Paypal does not support Card Payment but yes "Rest API sdk for Paypal" has the capability. Include this in your build.gradle: compile 'com.paypal.sdk:rest-api-sdk:1.2.5'
And then try the following method:
public static final String CLIENT_ID = "AQkquBDf1zctJOWGKWUEtKXm6qVhueUEMvXO_-MCI4DQQ4-LWvkDLIN2fGsd";
public static final String CLIENT_SECRET = "EL1tVxAjhT7cJimnz5-Nsx9k2reTKSVfErNQF-CmrwJgxRtylkGTKlU4RvrX";
/**
* #method getAccessToken is used to get AccessToken for performing authorised transcations
* #param clientId credential that we get when we register our application on https://developer.paypal.com/
* #param clientSecret credential that we get when we register our application on https://developer.paypal.com/
* #return String accessToken
*/
public static final String getAccessToken(String clientId, String clientSecret){
Log.i(TAG,"GetAccessToken called");
String accessToken = "";
long expiresIn;
try {
OAuthTokenCredential oAuthTokenCredential = new OAuthTokenCredential(clientId, clientSecret, getSdKConfig());
expiresIn = oAuthTokenCredential.expiresIn();
accessToken = oAuthTokenCredential.getAccessToken();
Log.i(TAG, "AccessToken: "+accessToken);
} catch (PayPalRESTException e) {
e.printStackTrace();
}
return accessToken;
}
/**
* #method makeDirectPayment is used for making direct payment via credit cards. Customers who don't have paypal account can pay via this method.
* #return String with Payment Id and Payment status
*/
public static final String makeDirectPayment(){
String accessToken = getAccessToken(Constants.CLIENT_ID, Constants.CLIENT_SECRET);
String message = "";
if (accessToken != null && !accessToken.equals("")){
APIContext apiContext = new APIContext(accessToken);
apiContext.setConfigurationMap(getSdKConfig());
CreditCard creditCard = new CreditCard();
creditCard.setType("visa");
creditCard.setNumber("4446283280247004");
creditCard.setExpireMonth(11);
creditCard.setExpireYear(2019);
creditCard.setFirstName("Test");
creditCard.setLastName("Shopper");
FundingInstrument fundingInstrument = new FundingInstrument();
fundingInstrument.setCreditCard(creditCard);
List<FundingInstrument> fundingInstrumentList = new ArrayList<>();
fundingInstrumentList.add(fundingInstrument);
Payer payer = new Payer();
payer.setFundingInstruments(fundingInstrumentList);
payer.setPaymentMethod("credit_card");
Amount amount = new Amount();
amount.setCurrency("EUR");
amount.setTotal("50");
Transaction transaction = new Transaction();
transaction.setDescription("Creating Direct Payment with Credit Card");
transaction.setAmount(amount);
List<Transaction> transactionList = new ArrayList<>();
transactionList.add(transaction);
Payment payment = new Payment();
payment.setIntent("sale");
payment.setTransactions(transactionList);
payment.setPayer(payer);
try {
Payment createdPayment = payment.create(apiContext);
if (createdPayment != null){
Log.i(TAG,"Payment object: "+createdPayment.toJSON());
message = "Payment Id: " + createdPayment.getId() + " Payment status: "+createdPayment.getState();
Log.i(TAG, message);
}
} catch (PayPalRESTException e) {
e.printStackTrace();
}
}
return message;
}
Note for simplicity I have used everything static but you can maintain your own UI to get no of items, its pricing, credit card details from user.
Allright, I have been struggling in understanding this authentification process with this "template" project and just don't get it.
What I am trying to do is a basic sign in, so I can get my authorization token, I've done it before by using SharedPreference (never actually used AccountManager) and accessing it from my rest android client (via a custom SessionManager).
So far, I was able to get the first part done. I am able to get my authorization token.
BoostrapAuthenticatorActivity.java:
/**
* Called when response is received from the server for authentication
* request. See onAuthenticationResult(). Sets the
* AccountAuthenticatorResult which is sent back to the caller. Also sets
* the authToken in AccountManager for this account.
*/
protected void finishLogin() {
final Account account = new Account(email, Constants.Auth.LZGO_ACCOUNT_TYPE);
if (requestNewAccount)
accountManager.addAccountExplicitly(account, password, null);
else
accountManager.setPassword(account, password);
final Intent intent = new Intent();
authToken = token;
userToken = user;
intent.putExtra(KEY_ACCOUNT_NAME, userToken);
intent.putExtra(KEY_ACCOUNT_TYPE, Constants.Auth.LZGO_ACCOUNT_TYPE);
if (authTokenType != null
&& authTokenType.equals(Constants.Auth.AUTHTOKEN_TYPE))
intent.putExtra(KEY_AUTHTOKEN, authToken);
setAccountAuthenticatorResult(intent.getExtras());
setResult(RESULT_OK, intent);
finish();
}
How do I have access to this value ? If you check this class,
BootstrapServiceProvider.java:
#Inject private ApiKeyProvider keyProvider;
#Inject private UserAgentProvider userAgentProvider;
/**
* Get service for configured key provider
* <p>
* This method gets an auth key and so it blocks and shouldn't be called on the main thread.
*
* #return bootstrap service
* #throws IOException
* #throws AccountsException
*/
public BootstrapService getService() throws IOException, AccountsException {
return new BootstrapService(keyProvider.getAuthKey(), userAgentProvider);
}
And finally, the provider:
ApiKeyProvider.java:
#Inject private Activity activity;
#Inject private AccountManager accountManager;
/**
* This call blocks, so shouldn't be called on the UI thread
*
* #return API key to be used for authorization with a {#link com.android.lzgo.core.LzgoService} instance
* #throws AccountsException
* #throws IOException
*/
public String getAuthKey() throws AccountsException, IOException {
AccountManagerFuture<Bundle> accountManagerFuture = accountManager.getAuthTokenByFeatures(Constants.Auth.BOOTSTRAP_ACCOUNT_TYPE,
Constants.Auth.AUTHTOKEN_TYPE, new String[0], activity, null, null, null, null);
Log.d("ApiKeyProvider", "ApiKeyProvider= " + accountManagerFuture.getResult().getString(KEY_AUTHTOKEN));
return accountManagerFuture.getResult().getString(KEY_AUTHTOKEN);
}
But this get me a null value! I'm at lost!
I'm not sure why the authtoken isn't getting applied correctly by setAccountAuthenticatorResult(...), however I've had luck by adding the following accountManager.setAuthToken(...) call in finishLogin()
if (authTokenType != null
&& authTokenType.equals(Constants.Auth.AUTHTOKEN_TYPE)) {
intent.putExtra(KEY_AUTHTOKEN, authToken);
accountManager.setAuthToken(account, authTokenType, authToken);
}
Perhaps this is related to not using Parse.com as our backend?