AWS Cognito works pretty well in our environment, we have roughly 7000 users.
However we have customers who cannot seem to find the verification emails that get sent out (and they have no idea what a spam folder is).
Is there a way as admin to email_verify them? Is there a way as admin to reset their password (and enter their new password for them) without a verification email?
I can't seem to find the right methods in the AWS Java SDK's AWSCognitoIdentityProviderClient.
You can call adminUpdateUserAttributes if you have access to the admin API. It is not explicitly documented, but email_verified is an attribute you can update.
Eg. Using the javascript aws sdk:
var params = {
UserAttributes: [ /* required */
{
Name: 'email_verified', /* required */
Value: 'true' //NEEDS TO BE A STRING
},
/* more items */
],
UserPoolId: 'STRING_VALUE', /* required */
Username: 'STRING_VALUE' /* required */
};
cognitoidentityserviceprovider.adminUpdateUserAttributes(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
Unfortunately, Cognito can't solve this problem directly. Currently, Cognito does not allow the developers to update the email_verified and phone_verified attributes. The only way these can be marked as true is through the code verification process. One workaround could be to use phone numbers instead of email addresses for verification.
Related
I am trying to implement authorization for this use case:
user can access only his own resources
admin can access everything
I am trying out Keycloak and it's resource server. For testing purposes and to understand these scopes and permissions and stuff, I have created test client weather-api and one resource Weather with url /weatherforecast.
Then I have scope weather:read and policy that every user with role weatherer can read that resource.
Now when I try to evaluate on a user with that role, I get PERMIT:
and another user without this role gets DENY.
so I guess my policies and permissions are set correctly.
When I try to use this from my service with user-managed-access disabled, I get permit too.
But when I enable user-managed-access, it fails.
I see in debug log that it gets permissions token:
{
...
"permissions": [
{
"scopes": [
"weather:read"
],
"rsid": "ae5ac493-b7dc-481e-9204-a664d1558a51"
}
],
...
}
but then the next message is
Policy enforcement result for path [http://192.168.0.9:5001/weatherforecast] is : DENIED
I tried to debug Keycloak library and found something I don't really understand.
In KeycloakAdapterPolicyEnforcer this part of code:
#Override
protected boolean isAuthorized(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, AccessToken accessToken, OIDCHttpFacade httpFacade, Map<String, List<String>> claims) {
AccessToken original = accessToken;
if (super.isAuthorized(pathConfig, methodConfig, accessToken, httpFacade, claims)) {
return true;
}
accessToken = requestAuthorizationToken(pathConfig, methodConfig, httpFacade, claims);
if (accessToken == null) {
return false;
}
...
}
private AccessToken requestAuthorizationToken(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade httpFacade, Map<String, List<String>> claims) {
if (getEnforcerConfig().getUserManagedAccess() != null) {
return null;
}
...
}
so when UserManagedAccess is not null, requestAuthorizationToken returns null and then it acts like the user is unauthorized with HTTP 401.
What am I missing here? Why it works only without UMA?
I have looked at these (app-authz-uma-photoz, devconf2019-authz) examples and haven't noticed what I am missing.
Except they are actually creating some resources for users from the Java app, I'm not. But I guess it shouldn't matter if I'm protecting user created resources or single "pre-made" URL, right? It should depend only on correct permissions and since they evaluate to PERMIT so I don't see why this doesn't work.
And one more question. Isn't this UMA thing overkill for just "user can access his own, admin can access everything" case when there will never be any sharing between users? I was thinking about some simpler way that could work without creating user resources in Keycloak but I couldn't think of anything, I believe I still need to have connected user ID with some resource ID to make this working.
I decided to use Fine Uploader for my current AngularJS project (which is connected to hosted on Firebase) because it has many core features that I will need in an uploader already built in but, I am having trouble understanding how to use Firebase's email & password authentication method to communicate with AWS (Amazon Web Services) to allow my users to use Fine Uploader S3 to upload content. Based on Fine Uploader blog post Uploads without any server code, the workflow goes like:
Authenticate your users with the help of an identity provider, such as Google
Use the temporary token from your ID provider to grab temporary access keys from AWS
Pass the keys on to Fine Uploader S3
Your users can now upload to your S3 bucket
The problem is that I won't be using OAuth 2.0 (which is used by Google, Facebook or Amazon to provide user identities) to allow my user's to sign into my app and upload content. Instead I will be using Firebase's email & password authentication.
So how can I make Firebase's email & password authentication method create a temporary token to grab temporary access keys from AWS and pass those keys on to Fine Uploader S3 to allow my users to upload content to S3?
To connect AWS with an outside application, Cognito is going to be a good solution. It will let you generate an OpenID token using the AWS Node SDK and your secret keys in your backend, that you can then use with the AWS JavaScript SDK and WebIdentityCredentials in your client.
Note that I'm unfamiliar with your specific plugin/tool, but this much will at least get you the OpenID and in my work it does let me connect using WebIdentityCredentials, which I imagine is what they are using.
Configure Cognito on AWS
Setup on Cognito is fairly easy - it is more or less a walkthrough. It does involve configuring IAM rules on AWS, though. How to set this up is pretty project specific, so I think I need to point you to the official resources. They recently made some nice updates, but I am admittedly not up to speed on all the changes.
Through the configuration, you will want to setup a 'developer authenticated identity', take note of the 'identity pool id', and the IAM role ARN setup by Cognito.
Setup a Node Server that can handle incoming routes
There are a lot of materials out there on how to accomplish this, but you want to be sure to include and configure the AWS SDK. I also recommend using body-parser as it will make reading in your POST requests easier.
var app = express();
var bodyParser = require('body-parser');
var AWS = require('aws-sdk');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
Create POST Function to talk with Cognito
Once you have your server setup, you then reach out to Cognito using getOpenIdTokenForDeveloperIdentity. In my setup, I use authenticated users because I expect them to come back and want to be able to continue the associations, so that is why I send in a UserID in req.body.UserIDFromAngularApp.
This is my function using express.router().
.post(function(req, res) {
if(req.body.UserIDFromAngularApp) {
var cognitoidentity = new AWS.CognitoIdentity();
var params = {
IdentityPoolId: 'your_cognito_identity_pool_id',
Logins: {
'your_developer_authenticated_identity_name': req.body.UserIDFromAngularApp
}
};
cognitoidentity.getOpenIdTokenForDeveloperIdentity(params, function(err, data) {
if (err) { console.log(err, err.stack); res.json({failure: 'Connection failure'}); }
else {
console.log(data); // so you can see your result server side
res.json(data); // send it back
}
});
}
else { res.json({failure: 'Connection failure'}); }
});
If all goes well, that will return an OpenID Token back to you. You can then return that back to your Angular application.
POST from Angular, Collect from Promise
At the very least you need to post to your new node server and then collect the OpenID token out of the promise. Using this pattern, that will be found in data.Token.
It sounds like from there you may just need to pass that token on to your plugin/tool.
In case you need to handle authentication further, I have included code to handle the WebIdentityCredentials.
angular.module('yourApp').factory('AWSmaker', ['$http', function($http) {
return {
reachCognito: function(authData) {
$http.post('http://localhost:8888/simpleapi/aws', {
'UserIDFromAngularApp': authData.uid,
})
.success(function(data, status, headers, config) {
if(!data.failure) {
var params = {
RoleArn: your_role_arn_setup_by_cognito,
WebIdentityToken: data.Token
};
AWS.config.credentials = new AWS.WebIdentityCredentials(params, function(err) {
console.log(err, err.stack);
});
}
});
}
}]);
This should get you on your way. Let me know if I can help further.
Each OAuth provider has a slightly unique way of handling things, and so the attributes available in your Firebase authenticated token vary slightly based on provider. For example, when utilizing Facebook, the Facebook auth token is stored at facebook.accessToken in the returned user object:
var ref = new Firebase(URL);
ref.authWithOAuthPopup("facebook", function(error, authData) {
if (authData) {
// the access token for Facebook
console.log(authData.facebook.accessToken);
}
}, {
scope: "email" // the permissions requested
});
All of this is covered in the User Authentication section of the Web Guide.
The accounts-foobar packages all rely on oauth-based authentication systems, and involve quite a bit of confusing, undocumented boilerplate. I'm wondering if there's an easy way to create a package for a non-oauth authentication system that will integrate normally with the Meteor accounts system. The non-oauth system I have in mind is a simple external API that just accepts a username and password, and returns a simple json object with success data or an error.
Is there a simple way to do this? Does Meteor provide an API for this that I've missed?
EDIT: This bit works fine, I'm just not entirely sure how to hook this up to the accounts system:
HTTP.post('https://my-site.com/api/login.json', { params: { username: 'foo', password: 'bar' } }, function (error, result) {
if (result) console.log('User data:', result.data);
});
// User data: { userId: 217, username: "foobar" }
It looks like Meteor's accounts-password packages should work for you (simple username/password based auth), however if you need something custom you can do it yourself.
You can roll your own auth package if you don't want to use any of the built in accounts-* packages. You simply need to register your own login handler and do a little bit of bookkeeping to keep the sessions authenticated on reconnects.
Step by step:
1: Add accounts-base package: meteor add accounts-base
2: On the server, add a Accounts.registerLoginHandler call
Accounts.registerLoginHandler(function(loginRequest) {
// ... check loginRequest for proper credentials - up to you
var userId = something; // determined by the credentials check
// add a resume token so that Meteor can resume your session on reconnect
var stampedToken = Accounts._generateStampedLoginToken();
Meteor.users.update(session.user,
{$push: {'services.resume.loginTokens': stampedToken}});
return {
id: userId,
token: stampedToken.token
});
3: Call login on the client
var loginRequest = { ... your auth credentials ... };
Accounts.callLoginMethod({
methodArguments: [loginRequest],
userCallback: function (err) {
if (!err) { ... do stuff here on successful login ... }
}});
That's it!
I'm trying to create a password reset mechanism and am stuck. Any suggestions how to do this with Firebase basic email/password authentication
[Engineer at Firebase - Update 2014-01-27]
Firebase Simple Login now supports password resets for email / password authentication.
Each of the Simple Login client libraries has been given a new method for generating password reset emails for the specified email address - sendPasswordResetEmail() on the Web and Android, and sendPasswordResetForEmail() on iOS.
This e-mail will contain a temporary token that the user may use to log into their account and update their credentials. This token will expire after 24 hours or when the user changes their password, whichever occurs first.
Also note that Firebase Simple Login enables full configuration of the email template as well as the sending address (including whitelabel email from your domain for paid accounts).
To get access to this feature, you'll need to update your client library to a version of v1.2.0 or greater. To grab the latest version, check out https://firebase.google.com/docs/.
Also, check out https://firebase.google.com/docs/auth/web/password-auth for the latest Firebase Simple Login - Web Client docs.
This is something that Firebase doesn't do very well. As you'll notice it requires the user to remember their old password. Usually if you want to reset a password it's because you've forgotten it. Hopefully the improve the methods they provide for account management.
https://www.firebase.com/docs/security/simple-login-email-password.html
authClient.changePassword(email, oldPassword, newPassword, function(error, success) {
if (!error) {
console.log('Password change successfully');
}
});
This was the first google result that came up when trying to figure out my issue.. for anyone who uses yeoman angularfire generator but would like to add the send email feature, this should work.
add the following to the simple login factory in simpleLogin.js:
resetPassword: function(emailIn){
return auth.$resetPassword({
email: emailIn
}, function(error) {
if (error) {
switch (error.code) {
case "INVALID_USER":
console.log("The specified user account does not exist.");
break;
default:
console.log("Error resetting password:", error);
}
} else {
console.log("Password reset email sent successfully!");
}
});
},
and call it from your login.js file
$scope.resetPassword = function(email){
simpleLogin.resetPassword(email)
};
In our app we had some actions that we required the user to reauthenticate before proceeding. We used code like below to make this happen.
FB.login(
function(response) { /* code here */ },
{auth_type: 'reauthenticate', auth_nonce: '...'}
);
It looks like the auth_type option is no longer supported, because I am getting the following log message: 'FB.login() called when user is already connected.' and the user is not being asked to reauthenticate.
Does anyone have any ideas how to reauthenticate after the changes for OAuth 2.0?
It appears that, for the time being (and I qualify that because Facebook seems to change their API response on a whim), you can get auth_type: reauthenticate to work properly IF you also specify permissions (the scope parameter in OAuth 2.0). Check out this example:
http://www.fbrell.com/saved/a78ba61535bbec6bc7a3136a7ae7dea1
In the example, click Run Code, and then try the "FB.login()" and "FB.login() with Permissions" buttons. Both are coded to use auth_type: reauthenticate, but only the latter actually gives you the FB prompt once you are logged in.
Here are the relevant examples:
// DOES NOT PROMPT
document.getElementById('fb-login').onclick = function() {
FB.login(
function(response) {
Log.info('FB.login callback', response);
},
{ auth_type: 'reauthenticate' }
);
};
// PROMPTS AS EXPECTED
document.getElementById('fb-permissions').onclick = function() {
FB.login(
function(response) {
Log.info('FB.login with permissions callback', response);
},
{ scope: 'offline_access', auth_type: 'reauthenticate' }
);
};
So, the answer is, Yes, auth_type: reauthenticate DOES work, but ONLY if you also specify a valid scope parameter. (And yes, I tried it with an empty scope, and it acted the same as not using scope at all.)
You can use an iframe to make sure the cookie is always valid.
facebook auto re-login from cookie php
Using FacebookRedirectLoginHelper::getReAuthenticationUrl everything works fine.
Internally the method put 'auth_type' => 'reauthenticate' and pass also all the permissions required.
Now the issue is that only prompt to the user to re-enter the password without the possibility to "switch" between users or without the possibility to insert also the username.
Does someone found a solution for this issue?
I manage an application with multi accounts and when the user need to generate again the token this is an issue :(
Thanks, Alex.