I'm trying to implement OpenID authentication for my site. Here's the scenario:
I want the user to be able to
login using just openId(user can just get verified by visiting openid provider. no need to create a custom account with email-password),
Via email/password (user has registered in site by filling out a form)
Attach open id(s) to his/her accounts (openids + email for one account).
Now I don't know what credentials I should store for open id. and not sure about the DB schema. Here's the database schema:
Table: Users
UserId => PK
... => Custom info. Not related to authentication.
Table: Authentication
AuthenticationId => PK
LoginId => (when custom site membership => email address) (when openId => openid unique address)
UserId => FK to Users.
Provider =>(when custom site membership => "CUSTOM") (when openId => openid provider address)
Password => filled when using custom membership. empty when using open id.
Now when a user logs in, whether by using openid/custom membership, I just look at authentication table and look for credentials and get the appropriate user. If no users exist, I create a new user and add an entry in authentication table.
The main question: Is storing Provider and LoginId (see the above comments to see what is being stored in these fields) enough for storing openid authentication? Should I store any additional data so that when the user returns I can authenticate him/her based on my saved data?
Do you suggest any other (more efficient) approach to implement this?
Thank you.
Store the ClaimedIdentifier for the openid user--not the Provider address. The Claimed Identifier is what the OpenID protocol verifies is unique for the user and also potentially provides portability across OpenID Providers.
Also, because OpenID 2.0's Claimed Identifiers may be deprecated by OpenID Connect (an unfinished successor to OpenID 2.0), it may also be in your best interest to record the OpenID Provider Endpoint URI and the email address asserted by the Provider in the user record. For now, do not use these as part of your authentication flow, but by recording them, you'll be able to later determine which email addresses you 'trust' (i.e. suppose you decide email addresses asserted by Google are trustworthy) and allow the user to thereby migrate their account to an OpenID Connect one using that verified email address. This will also mitigate against the danger of your web site's Realm (usually http://yourdomainname.com) changing and causing all your Google's user Claimed Identifiers to change, which can only really be recovered from via their email address, tragically.
I also recommend you use different tables for the different auth types. There are a couple of advantages here. The most important one is that architecturally it makes it more difficult to have introduce a security hole into your web site that might allow someone to enter in (for example) an OpenID into the username field and a blank password and have it show up as a database match and login without any real authentication happening. Secondly, it provides a more flexible model in case you want to add a third authentication mechanism rather than making your 'Authentication' table grow horizontally for all users. For example, OAuth 2.0 and "OpenID Connect" will each probably introduce new types of authentication to your site when you add support for them over the years, and adding new tables to handle the new types of data seem to fit better.
We just store the openid claim url. You may want to request additional information from the provider such as the user's name. The most important thing is to separate membership and authentication.
Our schema was
Profiles
--------
UserId
FirstName
LastName
etc.
Users
-----
Username
Password
Profiles.UserId is simply a string property that stores either the users internal username or their openId claim url, depending on how they registered.
Upon successful authentication (either using an internal username/password or external provider) we just set their authentication cookie using either their internal username or their claim url. Getting the user's profile is then just a matter of finding the profiler where (UserId == User.Identity.Name).
This has the advantage that a user can choose to change how they authenticate at any point (perhaps switching to an internal account or using a different provider).
Related
I have been trying to create an authentication in Laravel that is based on simple verification via an external services API key. The external API will provide me details like the username associated with the account a user should only have to supply an API key to login. No password, email, or username required.
Looking at Laravel's documentation it seems like using something like they demonstrate in the "Manually Authenticating Users" section may be most applicable. My problem is that this still appears to be based on a email + password credential model.
What is the proper way to modify/extend the frameworks authentication system to use an API key. If I use this manual authentication model I would be able to connect to the API and verify the user but I don't know the best way to modify it to accept an API key and username as the "credentials" for a new account (username would be coming from the API response data).
My goal is to create a single click registration / sign on for my site using social media that's painfree yet secured using oauth and SocialAuthenticationFilter.
Ideally you'd be able to login to the same account with either twitter / Facebook etc (without first connecting them to a user account).
An example I'm working from is the Spring Social Showcase found on git, it's fantastic but it still requires an intermediary 'sign up' step.
I can't figure out a way of making a secure account using only the info from Facebook login using aouth and I'd prefer it if a user didn't have to sign up and connect as per the example.
So, is there a secure way of doing this or am I misunderstanding something?
Thanks
Using OAuth / OIDC is the right way to go.
In order to automatically match the logins from different social login providers, you have to rely on the email address as the primary user identifier.
Once relying on the email address, you may automatically register new users inside your internal DB.
However users may want to change their email address. This may complicate the processes significantly, depending on what options you want to support.
We are trying to use Spring SAML Extension to implement identity federation which is a use case described in Security Assertion Markup Language (SAML) V2.0 Technical Overview (5.4.3 Federation Using Persistent Pseudonym Identifiers).
Our application try to associate remote users with local accounts(in out app) for SSO between business partners. Our application is a SP and partner's application is a IDP.
In this scenario, if a user attempt to access secure resource and does not have logon session on our app, the SP will redirect user to IDP. After user is authenticated at IDP site, a HTTP request will send to SP Assertion Consumer Service with a name identifier. At SP site, if the name identifier was not mapped to a local account, our app will present a login page to challenge user to provide local identity of our app. After user provider valid credential then a local session is created and user can access secure resource. Also a federation of two account (SP and IDP) is created and persisted.
I have searched many examples but have not found a configuration that clearly describes what I need. I have not found a Spring document that describes how I can implement this.
Basically, my questions are how to create/config custom login screens and persist this identity federation. Any thoughts, examples or documents?
btw, this is very similar to Account Linking in Ping federation.
Thanks for any help, much appreciated.
One approach to go about it is to:
implement a custom SAMLUserDetailsService which maps content of the Assertion (persistent NameID) to the local account
in case the local account exists it populates e.g. a UserDetails object with user's data and adds a GrantedAuthority e.g. ROLE_FULL_ACCESS
otherwise it returns an object which indicates that local account is missing, but doesn't throw an exception
implement a custom AuthenticationSuccessHandler which detects whether user has a local account (based on the Authentication object with data populated from the SAMLUserDetailsService)
in case user has a local account continue to the default page
otherwise redirect user to page with challenge for linking of the local identity
implement e.g. an MVC Controller, or another Spring Security authentication endpoint which accepts callback from the local identity linking page (with user's credentials to the local account)
store the link between persistent ID and local account
update the current Authentication object with the new UserDetails object reflecting the selected local account
redirect user to the default page
Content which should be available only to fully authenticated users (i.e. users with local account) should be secured with role ROLE_FULL_ACCESS, so it cannot be accessed by users who authenticated using the IDP, but who haven't performed the linking yet.
In my application I need to register users. The users can be any of three: admin, client and general. They have different attributes (Admin may have only name, client may have company address and so on). The default MVC membership scheme is okay but how can it be extended to register more information during registration time? Or should I use custom membership?
I need to have a record of clients and general users with clientID or generalID.
The default MVC membership scheme is okay but how can it be extended
to register more information during registration time? Or should I use
custom membership?
I think too many people, yourself included, are expecting to get too much from the default ASP.NET Membership Provider. It was never designed to handle application-specific things, like what company your customer works for, your admin's name, and so on. It's main purpose is storing passwords for authentication.
Sure, the password needs to be linked to a username, so that there can be a 2-key authentication pair. Sometimes you also need the user's email address, when it is different from their username, in order to contact the user regarding their password. But don't store anything else about your users in the membership store. Store it in your application database.
In order to join data between your application and the membership provider, use the membership provider's UserName or ProviderKey as a column in one of your database tables. You end up with 2 entities which are not explicitly related. You can even have your SqlMembershipProvider implemented in a separate database from your application database. Even if they are in the same database, avoid having a foreign key between any of the provider tables and your application tables. This muddies the waters between what you own, and what you "outsource" to the membership provider.
You end up with 2 physically isolated representations of your user. One is the MembershipProvider, which contains a password for your user. The other is your application, which contains other business-specific details. The two are only logically associated within your application. After you authenticate a user with the membership API, their UserName and/pr ProviderKey become available to your application. You can then use that piece of data to query your app database and get the additional details. This is where you might put something like the clientID or generalID you mentioned.
If you look at the System.Web.Security.Member* API, this should make things clearer. It does one thing really well -- associating your users with passwords and other information related to password resetting (like the email address, question and answer, etc). So outsource just the password provider, and rely on your application to do the important stuff.
You could customise the default profile provider or create your own... Follow this reference
http://msdn.microsoft.com/en-us/library/8zs47k7y
You can add new properties to the profile for anything in the web.config too
I highly suggest creating your own membership roles. It's dead simple and nothing can beat the flexibility of having your own implementation.
Here's a video I made a while back showing you step by step how to achieve this:
http://www.youtube.com/watch?v=BsxUsyMSGeA
The gist of it is, you create your own AuthorizeAttribute and create your own roles; protecting each controller or even individual Action methods along the way.
The one drawback of this approach is that you can determine what Role a user has in your system, but not what a Role can do in your system. Does that make sense?
There are other choices if you need to edit what a role can do at runtime.
We are building an ASP.NET MCV 3 application from scratch running on Windows Azure. About Authentication and Authorization layer we are thinking to use the Access Control Service. I went through some articles about ACS where I got the basic idea but I still have some doubts on it.
My understanding is that using the ACS we outsource the Authentication process to one or more Identity Providers (IP), basically we trust another system (i.e. Microsoft Live ID) to authenticate our users.
The basic process is very straightforward: at authentication stage we redirect (ACS does it) the user to one of our “trusted” IPs, that will redirect the user (with a valid token) to the ACS and eventually to our application.
Here comes a number of questions:
Since we don’t want that all the users with a Live ID account can access to our application, I presume there should be another process to validate that user and checking if he is registered in our application. The question is where? In the ACS or in our application?
I have an idea about this but I don’t know if it’s the right way to do it:
At registration stage, the system (our web app.) asks the user which IP (i.e. Live ID, Google, Facebook, and our app.) he wants to use to authenticate himself in the application. Then the user goes through the authentication process on the IP system and when he comes back, we store his username (IP username) in our DB.
So, next time, at authentication stage we can check if that user is registered in our system.
If the above theory is correct, that means in our app. we need to build our membership provider to store usernames coming from IPs and users that chose our app. as IP.
Am I correct? What is the best practice to design the above process?
Now let’s talk about Authorization and “Roles”. How does it work with ACS? Does ACS manage multiple roles per user?
Again my understanding is that with ACS you can create a number of “Rule groups” related to the IP and not to a single user. If this is correct, how do we manage users in role in our application? Let’s say, for example, that we have multiple roles and our users can be associated to those roles, can we use ASC to manage it?
So the final questions are: Does ACS itself cover the whole Authentication and Authorization process? Do we still need to use the .net Membership Provider? What's the best practice in order to cover our requirements?
For the part of the question about the registration stage, the best thing to use to identify users is the NameIdentifier claim type
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier.
This should be unique for each identity provider and also fixed. If you use the email address claim, it could change for the same user. Technically it could be possible for two identity providers to use the same NameIdentifier (none of the out-of-the-box ones with ACS do) so you could combine the NameIdentifier claim with the IdentityProvider claim type
http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider
to guarantee uniqueness.
For the part about role, I would say using ACS to issue role claims from generic identity like Google would be quite hard to manage using the claim transformation rules in ACS on per user basis. You would have to add a rule for each registered user - probably not feasible. I think the ACS rule groups are more suited to transformation of role claims (e.g. issued by a federated ADFS). Your idea to do it in your application is a better one IMHO. In code, the place to do this using WIF is in a custom ClaimsAuthenticationManager. You override its Authenticate method and based on the NameIdentifier claim from the incoming principle, you look up in your membership datastore and create a new IClaimsPrinciple based on the roles that are in your membership DB (i.e. you add a role claim for each role the user is in).
You then make your authorization decision in a custom ClaimsAuthorizationManager. There are some good samples and info on this around on the web. You can start at
http://msdn.microsoft.com/en-us/library/ee748497.aspx
The user validation process is done with claims.
After you set up an IP with ACS, when users authenticate, ACS will get claims about the authenticated user from the IP. You need to configure rules in ACS to say which claims you want forwarded on to your application. You can also tranlate claims into different types, to normalize the incoming claim set to what your application expects
If you want to implement your role based access with ACS, you can. In this case a role just another claim ACS will issue, and you'll implement your application to give user privileges based on the role claim it receives from ACS.
You can configure ACS rules that map certain IP input claims to role output claims. ACS also has a management service that can change these rules so you can implement a user registration process.
Individual claim rules in ACS relate to identity providers that issue the claim, but rule groups don't. Rule groups associate to RPs (your applications). A rule group is simply a group of claims transformation rules that tell ACS: "for this application, apply this rule group policy when you issue the token".
The ACS docs have lots to say about ACS claim rules configuration, both through the web portal and through the management service::
https://msdn.microsoft.com/library/azure/hh147631.aspx
Expanded response:
Let's say you're using ACS to authenticate to an ASP.NET app that's using WIF. You would configure ACS to issue a Role claim of "Manager" for the google user with email "jdoe#gmail.com".
Now in your ASP.NET app, WIF will see this role claim and it will allow you to control access using either HttpContext.Current.User.IsInRole("Manager"), or the web.config equivalent.
You can manage these ACS rules manually using the web UI, or you can implement a registration process that adds such rules to ACS programatically using the ACS management service. There are some ACS management service samples available at acs.codeplex.com.
Also, the identity developer training kit has some examples on WIF role based access:
http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=14347