I am new to AWS Cognito.
From my program, I want to get AWS temporary credentials to access API services such as api from API gateway. What I have is "IdentityPoolId", "IdentityId" and "OpenIdToken".
When I tried accessing with AWS Credential by getCredentialsForIdentity, I got "Identity 'ap-northeast-1:xxxx' not found." at onError method everytimes. Please help me what I was wrong?
Single<GetCredentialsForIdentityResult> primeSingle = Single.fromCallable(MyClass::getResult);
primeSingle
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<GetCredentialsForIdentityResult>() {
#Override
public void onSubscribe(#NonNull Disposable d) {
}
#Override
public void onSuccess(#NonNull GetCredentialsForIdentityResult result) {
Credentials credentials = result.getCredentials();
}
#Override
public void onError(#NonNull Throwable e) {
Log.d("Test", "onError: " + e.getMessage());
}
});
Here is getting Credential Result code.
private static GetCredentialsForIdentityResult getResult() {
AmazonCognitoIdentity identityClient = new AmazonCognitoIdentityClient(new AnonymousAWSCredentials());
Map<String, String> logins = new HashMap<String, String>();
logins.put("cognito-identity.amazonaws.com", MyClass.OPEN_ID_TOKEN);
GetCredentialsForIdentityRequest getCredentialsForIdentityRequest =
new GetCredentialsForIdentityRequest()
.withIdentityId(MyClass.IDENTITY_ID) // Not Identity Pool Id
.withLogins(logins);
getCredentialsForIdentityRequest.setIdentityId(identityId);
GetCredentialsForIdentityResult result = identityClient.getCredentialsForIdentity(getCredentialsForIdentityRequest);
return result;
}
Finally, I got Credentials by referencing this.
https://docs.aws.amazon.com/cognito/latest/developerguide/developer-authenticated-identities.html
Thanks in advance.
Here is the code:
public class DeveloperAuthenticationProvider extends AWSAbstractCognitoDeveloperIdentityProvider {
private static final String developerProvider = null;
public DeveloperAuthenticationProvider(String identityPoolId, Regions region) {
super(null, identityPoolId, region);
// Initialize any other objects needed here.
}
// Return the developer provider name which you choose while setting up the
// identity pool in the &COG; Console
#Override
public String getProviderName() {
return developerProvider;
}
// Use the refresh method to communicate with your backend to get an
// identityId and token.
#Override
public String refresh() {
// Override the existing token
setToken(null);
// Get the identityId and token by making a call to your backend
// (Call to your backend)
// Call the update method with updated identityId and token to make sure
// these are ready to be used from Credentials Provider.
update(identityId, token);
return token;
}
// If the app has a valid identityId return it, otherwise get a valid
// identityId from your backend.
#Override
public String getIdentityId() {
// Load the identityId from the cache
identityId = "ap-northeast-1:xxxx";
return identityId;
}}
Call above call from one method:
private static AWSSessionCredentials getResult(Context context) {
DeveloperAuthenticationProvider developerProvider =
new DeveloperAuthenticationProvider("ap-northeast-1:your_pool_id", Regions.AP_NORTHEAST_1);
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider( context, developerProvider, Regions.AP_NORTHEAST_1);
return credentialsProvider.getCredentials();
}
And use rxjava to get response:
Single<AWSSessionCredentials> primeSingle = Single.fromCallable(() -> getResult(this));
primeSingle
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<AWSSessionCredentials>() {
#Override
public void onSubscribe(#NonNull Disposable d) {
}
#Override
public void onSuccess(#NonNull AWSSessionCredentials result) {
String secretKey = result.getAWSSecretKey();
}
#Override
public void onError(#NonNull Throwable e) {
Log.d("Test", "onError: " + e.getMessage());
}
});
After successful, you can get Credentials from onSuccess method.
Related
I am able to do the initial log in to the server and get the token, but when I try to do another request I get the HTTP error 403, so I am not actually being authenticated.
When I go through the browser or the android application, this is the key that I am getting when I log in.
{
"key": "64ea43a78fa18da19364d2d0ae5a12371e5d0ee2"
}
Is there anything that I can do with this key using retrofit? I have tried using the header "Authorization" and following with the token.
Here is my RestClient interface:
public interface RestClient {
#POST ("rest-auth/login/")
Call<Token> login(
#Body Login body
);
#GET ("v2/users/{user}/")
Call<List<CustomUser>> getUser(
#Header("Authorization") String token,
#Path("user") String user
);
Here is the AsyncTask which will perform the requests to the server. The authenticateUser gives me an HTTP response of 200, but the syncUser gives 403.
public class ActionSync extends AsyncTask<String, Void, Boolean> {
RestClient client;
IData activity;
private static String token;
public ActionSync(Context context) {
activity = (IData) context;
}
#Override
protected Boolean doInBackground(String... params) {
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("http://" + params[2] + ":" + params[3] + "/")
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
client = retrofit.create(RestClient.class);
//Authenticate the user.
authenticateUser(params[0], params[1]);
//Once the authentication has been completed, we can now move on the syncing data.
syncUser(params[0]);
//If we get to the end without any errors, then return true. This means that the sync is complete.
return true;
}
#Override
protected void onPostExecute(Boolean loggedIn) {
super.onPostExecute(loggedIn);
}
public void authenticateUser(String username, String password){
//First, we must log into the server given our credentials. Otherwise, we will not be able to get any data.
Login login = new Login(username, password);
Call<Token> call = client.login(login);
call.enqueue(new Callback<Token>() {
#Override
public void onResponse(Call<Token> call, Response<Token> response) {
if(response.isSuccessful()){
Log.v("ActionSync", "Login was successful");
token = response.body().getKey();
} else {
Log.v("ActionSync", "Login was unsuccessful");
}
}
#Override
public void onFailure(Call<Token> call, Throwable t) {
Log.v("ActionSync", "Error occurred during login");
}
});
}
public void syncUser(String username){
Call<List<CustomUser>> call = client.getUser(token, username);
call.enqueue(new Callback<List<CustomUser>>() {
#Override
public void onResponse(Call<List<CustomUser>> call, Response<List<CustomUser>> response) {
Log.v("ActionSync", "The response from get user: " + response.toString());
}
#Override
public void onFailure(Call<List<CustomUser>> call, Throwable t) {
Log.v("ActionSync", "No response from get user");
}
});
}
public interface IData {
}
}
I am making a call to get a Firebase token, then using that token to get a token from my server.
I want userSignIn() to return the token from my server.
Does anyone know how can I return the token to userSignIn()?
#Override
public String userSignIn(String email, String password, String authType) throws Exception {
login(email, password, authType, new OnLoginResponseCallback() {
#Override
public String onLoginResponse(boolean success, String token) {
**return token;** // how do I return this to userSignIn???
}
});
}
public interface OnLoginResponseCallback {
public String onLoginResponse(boolean success, String token);
}
public void login(String email, String password, String authType, final OnLoginResponseCallback callback) throws Exception {
getFirebaseToken(email, password, new OnFirebaseTokenResponseCallback() {
#Override
public String onFirebaseTokenResponse(boolean success, String token) {
getAuthToken(token, null, new OnAuthTokenResponseCallback(){
#Override
public String onAuthTokenResponse(boolean success, JSONObject response){
try {
String access_token = response.getString("access_token");
callback.onLoginResponse(true, access_token);
}
catch (JSONException ex) {
}
}
});
}
});
}
public interface OnFirebaseTokenResponseCallback {
public String onFirebaseTokenResponse(boolean success, String token);
}
public void getFirebaseToken(String email, String password, final OnFirebaseTokenResponseCallback callback) {
FirebaseAuth auth = FirebaseAuth.getInstance();
auth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (!task.isSuccessful()) {
} else {
AuthResult result = task.getResult();
FirebaseUser user = result.getUser();
user.getToken(false).addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
#Override
public void onComplete(#NonNull Task<GetTokenResult> task) {
if (task.isSuccessful()) {
try {
String token = task.getResult().getToken();
callback.onFirebaseTokenResponse(true, token);
}
catch (Exception ex) {
}
} else {
}
}
});
}
}
});
}
public interface OnAuthTokenResponseCallback {
public String onAuthTokenResponse(boolean success, JSONObject response);
}
public void getAuthToken(String token, String refreshToken, final OnAuthTokenResponseCallback callback) throws JSONException {
RequestParams params = new RequestParams();
if (refreshToken != null)
{
params.add("grant_type", "refresh_token");
params.add("refresh_token", refreshToken);
}
else if (token != null)
{
params.add("grant_type", "urn:ietf:params:oauth:grant-type:firebase_token");
params.add("assertion", token);
}
else if (refreshToken == null && token == null)
{
params.add("grant_type", "password");
params.add("username", "");
params.add("password", "");
}
AuthClient.post("connect/token", params, new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, cz.msebera.android.httpclient.Header[] headers, JSONObject response) {
try {
callback.onAuthTokenResponse(true, response);
} catch (Exception ex) {
}
}
#Override
public void onFailure(int statusCode, cz.msebera.android.httpclient.Header[] headers, Throwable throwable, JSONObject response) {
callback.onAuthTokenResponse(false, new JSONObject());
}
});
}
UPDATE:
Thanks. I removed the redundant method, and call login like this:
.login(userName, userPass, mAuthTokenType, new OnLoginResponseCallback() {
#Override
public void onLoginResponse(boolean success, String token) {
data.putString(AccountManager.KEY_ACCOUNT_NAME, userName);
data.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType);
data.putString(AccountManager.KEY_AUTHTOKEN, token);
data.putString(PARAM_USER_PASS, userPass);
}
});
I think it works but haven't had a chance to fully test it yet. One thing I am not certain about is I am trying to modify "data" with a value from "token", yet "data" is a Bundle that is final, so I am not sure if that works or not. Will test later. Thanks.
You called a method that basically calls another method of the same signature
#Override
public String userSignIn(String email, String password, String authType) throws Exception {
login(email, password, authType, new OnLoginResponseCallback() {
#Override
Instead, wherever you would call userSignIn, you call login, and pass in that anonymous class. You can't return from these inner methods, because that isn't how callbacks work. You use the parameters of the interface methods to "continue" your logic. Like, do login, callback to the main function with some user info, use this info to make a new request, have a callback waiting for that data, that passes back data to some other method. It's all void methods calling other methods. No return statements
Although, in Javascript, you can read this
How to return value from an asynchronous callback function?
Why you want to return token from there that's not really clear as you are already under the method !!! You can do rest of the work within onLoginResponse() or by calling another method.
I'm new using retrofit2 and rxjava, i was able to use GET to get information from api's but now, using POST for a login request is not working how is suposed too.
Application application = Application.get(mLoginView.getContext());
Service Service = application.getmService();
Log.i(TAG,""+username);
Log.i(TAG,""+password);
mSubscription = Service.login(username,password)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<User>() {
#Override
public void onCompleted() {
Log.i(TAG,"User: " + mUser.getHash());
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
Log.i(TAG,"USERNAME DON'T EXIST");
}
#Override
public void onNext(User user) {
// LoginPresenter.this.mUser = user;
}
});
Service:
public interface Service {
String mUrl = "https://blabla.com/api/index.php/"; // TODO Change
#FormUrlEncoded
#POST("user/login")
Observable<User> login(#Field(value="email",encoded=true) String email, #Field(value="password",encoded = true) String password );
I enter a POST with username and pass from an existing user and return me a 404 page and not the hash im supposed to get.
Thank you
I forgot this was here, I found a solutions months ago, and what i did was create a object UserCredentials to do the body request and a object to get the response.
#POST("user/login")
Observable<LoginResponse> login(#Body UserCredentials userCredentials);
I decided to use Volley and go the RESTful route with Firebase since their listeners seem to hang when there's no internet connection. At least with Volley, it lets me know if a network request was not successful due to internet connection or not.
I need to know whether FirebaseUser auth tokens expire or not. In my app, I only allow Google and Facebook authentication, and I use the following code assuming that Firebase user auth token DO NOT expire:
private String authToken;
// Callbacks
public interface ApiCallbacks {
public void onSuccess(JSONObject response);
public void onError(String errorString);
}
private interface AuthTokenCallbacks {
public void onAuthTokenSuccess();
public void onAuthTokenError(String errorString);
}
// Request Helpers
private void getAuthToken(final AuthTokenCallbacks callbacks) {
// Lazy instantiation
if (authToken == null) {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user == null) {
callbacks.onAuthTokenError("Please log in");
} else {
user.getToken(false).addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
#Override
public void onComplete(#NonNull Task<GetTokenResult> task) {
if (task.isSuccessful()) {
authToken = task.getResult().getToken();
callbacks.onAuthTokenSuccess();
} else {
callbacks.onAuthTokenError("Please log in");
}
}
});
}
} else {
callbacks.onAuthTokenSuccess();
}
}
public void sendGetRequestTo(final String endpoint, final HashMap<String, String> arguments, final RequestQueue requestQueue, final String tag, final ApiCallbacks callbacks) {
// Only execute get request if we have an auth token
getAuthToken(new AuthTokenCallbacks() {
#Override
public void onAuthTokenSuccess() {
final String requestUrl = getRequestUrlString(endpoint, arguments);
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, requestUrl, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
callbacks.onSuccess(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
callbacks.onError(error.toString());
}
});
request.setTag(tag);
requestQueue.add(request);
}
#Override
public void onAuthTokenError(String errorString) {
callbacks.onError("Please log in");
}
});
}
Is this the correct way of doing it? I just need to know if I'm going in the right direction because I don't want future problems with my auth tokens expiring (if they do).
EDIT
I forgot to mention that my final String requestUrl = getRequestUrlString(endpoint, arguments); method basically constructs the url request string with auth=authTokenString appended at the end of my url.
Yes, they do expire (you can check out the expiration date at jwt.io). If you don't force a refresh (i.e. user.getToken(false)), the returned token will be updated only if it has expired. If you pass true to getToken(...), a new token will be created which also involves the linked providers' token validation on the firebase servers (e.g. validating against Facebook whether the user still has his/her account linked). Note that the latter counts towards your daily token service quotas, so make sure you use it only when it's necessary.
I'm logging in with twitter using Fabric.
This is how I fetch the user data:
loginButton.setCallback(new Callback<TwitterSession>() {
#Override
public void success(Result<TwitterSession> result) {
// Do something with result, which provides a TwitterSession for making API calls
AccountService ac = Twitter.getApiClient(result.data).getAccountService();
ac.verifyCredentials(true, true, new Callback<com.twitter.sdk.android.core.models.User>() {
#Override
public void success(Result<com.twitter.sdk.android.core.models.User> result) {
String imageUrl = result.data.profileImageUrl;
String email = result.data.email;
String userName = result.data.name;
System.out.println(imageUrl);
System.out.println(email);
System.out.println(userName);
}
#Override
public void failure(TwitterException e) {
}
});
}
This is working fine, except that the email variable is null when I print to log. Is there an other way of fetching the user email?
-Here is the Solution!
twitauthobj.requestEmail(twitsessionobj,new Callback<String>() {
#Override
public void success(Result<String> stringResult) {
'You code here'
}
#Override
public void failure(TwitterException e) {
}
});
-Thanks let me inform if t doesnt work!
To bypass Twitter's useless request email activity and to fix a leak, I dug through the source code and pulled this out:
new Retrofit.Builder()
.client(getClient(sessionResult))
.baseUrl(new TwitterApi().getBaseHostUrl())
.addConverterFactory(getFactory())
.build()
.create(EmailService.class)
.getEmail()
.enqueue(new Callback<User>() {
#Override
public void success(Result<User> result) {
String email = result.data.email;
// Handle the result
if (email == null) {
TwitterProvider.this.failure(
new TwitterException("Your application may not have access to"
+ " email addresses or the user may not have an email address. To request"
+ " access, please visit https://support.twitter.com/forms/platform."));
} else if (email.equals("")) {
TwitterProvider.this.failure(
new TwitterException("This user does not have an email address."));
} else {
mCallbackObject.onSuccess(createIdpResponse(sessionResult.data, email));
}
}
#Override
public void failure(TwitterException exception) {
TwitterProvider.this.failure(exception);
}
});
private OkHttpClient getClient(Result<TwitterSession> sessionResult) {
return OkHttpClientHelper.getOkHttpClient(
sessionResult.data,
TwitterCore.getInstance().getAuthConfig(),
TwitterCore.getInstance().getSSLSocketFactory());
}
private GsonConverterFactory getFactory() {
return GsonConverterFactory.create(
new GsonBuilder()
.registerTypeAdapterFactory(new SafeListAdapter())
.registerTypeAdapterFactory(new SafeMapAdapter())
.registerTypeAdapter(BindingValues.class, new BindingValuesAdapter())
.create());
}
EmailService:
interface EmailService {
#GET("/1.1/account/verify_credentials.json?include_email=true?include_entities=true?skip_status=true")
Call<User> getEmail();
}