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.
Related
I'm working on a web application that uses OpenId authentication. Let's assume that the application essentially serves to store metadata and its associated files (docx, pdf). The Web Application is for internal use and is not exposed to public network, only users of the organization have access.
Recently, a requirement has arisen to be able to share files with users external to the organization. External users will use a PORTAL (third-party application) which, through a URL generated by the Web Application that points to the PORTAL, will have access to the file. This PORTAL uses OpenId authentication and invokes a Web Application API to retrieve the file.
Initially, the proposed solution was:
Web Application - Send EMAIL to the external user and create a user in Keycloak with Email to authenticate later on the PORTAL (Is this really necessary?! Biggest doubt).
The external user accesses the PORTAL with the URL received and authenticates with the user created by the Web Application on Keycloak.
Once authenticated on PORTAL, a WebApplication API is invoked to obtain the file.
The main question is whether the Web Application should manage the creation/editing/deleting of external users on Keycloak. Does the Web Application need to create users in Keycloak? Is there another way to accomplish this without compromising security?
Thanks in advance.
To share a file with restricted access, there are two approaches:
Open access with signed links: Create a signed URL using a web API and share it with external users. The link can be a static URL with an encrypted key, or a JWT signed token in base64 form generated by the web API. When the portal receives a request, it checks the validity of the token, retrieves the file location from the token, and allows access.
Email-restricted access: If you want to guarantee access only to the person with email xxx#abc.com, you'll need to use a challenge, which is typically a login. You can either create users on the fly after login (if the external users come from a partner with OIDC capability), or pre-create the users if this is not the case.
Note: You cannot rely solely on a URL with an email claim as proof of access, as the link may have been forwarded to someone else.
I have implemented a Spring Boot application with AngularJS frontend. Have also setup users along with their permissions. Right now I am able to login with any of these users and is working well with Spring security. I would like to turn this traditional login flow into a Facebook/Google OAuth login flow, where in I want the users to use their Facebook/Google account to log in and they will be mapped to their internal users automatically. This will help me in getting rid of maintaining passwords of these users.
I found many articles talking about setting up OAuth with Spring Boot and how can Facebook/Google login be integrated with a Spring Boot application. But I am having difficulty in finding an article which talks about linking a Facebook/Google user with internal users.
How should I go about this?
Look for a user with the associated facebook/google userID.
If that user does not exist you request an email address and try to match it with an existing legacy account.
If you do not get a email adress for any reason (not acceping the authorization request for example) you could show a popup box asking for the email adress explaining why you need it.
You then locate the legacy user and merge it adding the facebook/google ID to look it up in the future.
If no user is found with the email adress you either refuse the user or create a new account.
you should be able to do all of this by implementing your own AuthenticationProvider
Before you can fetch a user’s data from Facebook, you must specify your application’s ID and secret by setting the spring.social.facebook.appId and spring.social.facebook.appSecret properties. You can set these via any means supported by Spring Boot, including setting them in an application.properties file:
spring.social.facebook.appId=233668646673605
spring.social.facebook.appSecret=33b17e044ee6a4fa383f46ec6e28ea1d
For reference you can follow this article: https://spring.io/guides/gs/accessing-facebook/
I have an MVC application (.Net Framework 4.5) which is been there for the last three years and using Forms Authentication mechanism. This application provides different accounts like Personal, freebie, Enterprise etc. For an enterprise account, we are handling everything in the same application. I.e. Suppose an enterprise called “xyz” created an enterprise account with the application, then we are providing a custom URL like “https://application/xyz/login” and from the URL we are identifying that enterprise. I don’t know the exact reason why they implemented like this as I have seen applications that are having enterprise accounts are created as subdomains (e.g. https://xyz.okta.com). Now the client asked to integrate Okta into this application.
So I looked into Okta and found SAML is the right way to do and ends up in KentorIT Authservices. Initially, I was able to integrate this with a sample MVC application and the authentication part was working fine. With some basic idea about SSO, I have started integrating kentor authsevices into my application. The challenges I found in this implementation are:
1) For Enterprise accounts, Okta configuration settings are different for each enterprise and with my current application implementation, it is not possible to set it in from the web.config. So I have tried to set it from code and I was able to integrate those settings by replacing Configuration.Options.FromConfiguration;. I’m planning to store all configuration related things(Single sign-on URL, Audience URI,Identity Provider Issuer" etc.) in the database so that I can get the information whenever I wanted and I’m assuming that “Identity Provider Issuer Id is unique for each Okta account. In an IdP initiated flow, when the user tries to access the application it will redirect to AuthServices\Acs action method and from that, I’m trying to read the configuration settings. From the request is there any way I can identify from which Okta account call came(like Identity Provider Issuer)? Currently, I set the "Identity Provider Issuer" value (and I think which should be unique for okta account) to the Default RelayState field under General SAML settings tab and I was able to retrieve it from AuthServices\Acs action methods. Does it seem to be a good idea? Please advice.
2) The Enterprise accounts are limited based on the number of licenses (say 50). Suppose if the Enterprise Okta admin intentionally added 55 users all those users can successfully authenticate the application based on the default settings. Is there any way I can handle this scenario. Do I need to keep a record of the list of users that came under a particular enterprise account?
3) From the documents I understand that Kentor authentication service is only for authentication and authorization part has to be done from the application itself. The current application implementation consists of a custom authorization attribute which checks for user permissions that are stored in the database. That should be there as it is and we have to do the authorization based on database permissions. Right?
Expecting your valuable suggestions and please correct me if I'm wrong. Thanks in advance.
Don't use the RelayState for sensitive data unless you cryptographically sign it. It is not protected by any signature when using the POST binding, so the user may manipulate it. To get the issuing idp, check the issuer field of any claim generated by AuthServices instead.
Yes.
Yes, that's the whole idea with Kentor.AuthServies: To plug SAML2 authentication into the security model of .NET to allow you to use any current/traditional Authorization setup.
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).
We are having a hosted web application and it uses forms authentication.
This webapplication is accessed by users belong to different partner organizations.
Currently users belong to the partner organizations are accessing the application using the credentials that we give it to them.
Now, some partner organizations wants their users to access the application using their active directory credentials.
We are planning to use ADFS for these partner organizations, so the users will be authenticated using Active Directory within their network and claims will be sent to the webapp via the Authentication token cookie set by the ADFS. From the claims, we map the users to the internal userIds of the web application.
My questions are , if we make the web application ADFS enabled,
1)Is it possible to still allow the other partner organization users(who don't want to use ADFS) to login to the web application using the existing login page(forms authentication)?
2) Should every page in the ADFS enabled webapp be accessed through https?
Any solutions or pointers would be much appreciated.
Thanks
-arul
Your app needs to require claims that describe the user, regardless of where they login from. It should not handle authentication in either case; this should be delegated to a trusted issuer, an STS. This will allow it to interact w/ users in a uniform way irrespective of where and how they authenticate. This means that you're going to need to use ADFS in two roles: that of an Identity Provider (IP) STS and of a Federation Provider (FP) STS. For users of partner companies that don't want to maintain users themselves, you'll be the IP-STS; for those that do, you'll be an FP-STS. In the latter case, ADFS will redirect users from your realm back to the partner's site where their IP-STS will authenticate them and send them to your FP-STS. It will map your partner's user ID and claims into ones that make sense in your realm. This and other information about the user will be included in the set of claims that are issued from your FP-STS. As a result, your app, only trusts your STS regardless of which scenario is appropriate for different users. Note that in this scenerio, there will be two STSs: your ADFS FP-STS and your partner's IP-STS, which may or may not be ADFS. In the other case, there will only be one STS: your IP-STS.
Not every page on your ADFS Web app needs to be accessed via HTTPS; however, everyone that's used in the authentication process should be.
This is really a non-trivial undertaking. If you want to talk about it more, please feel free to get in touch w/ me.