SSO & Existing OAuth integrations - authentication

Good Evening,
My group is rolling out SSO - yay. We have several applications that directly authenticate with Box.com and all token refreshes are handled automatically. After we migrated to SSO, we didn't include these service (app) accounts in our AD, so they do not have access via the SSO gateway.
My (likely incorrect) understanding of how OAuth with an SSO provider in the loop works:
We can still start the OAuth handshake directly with box - but box will forward this request to the SSO provider. The SSO provider will then authenticate the credentials and pass back a "all good" to box, which will issue an auth_token.
This is based off of the following from box:
"If you authenticate your application via Box’s OAuth 2.0, your
application will automatically let the customer sign-on with their
company credentials, just like they do with every other Box
application. This also applies to popular commercial services like
Okta, One Login, and Ping."
https://docs.box.com/docs/oauth-20
As well as this photo:
So if the external applications' service accounts with Box aren't in the AD of the SSO (too many acronyms), they should not be able to authenticate right?
But these apps are continuing to be able to authenticate. They are able to refresh their token and continue accessing box, even after the migration to SSO.
Where is the flaw in my understanding? Will these apps need to be added to the AD, or does this roll out of SSO not affect any of our external dependencies?
Thanks!

Got an answer from box:
third-party apps and integrations use a persistent authentication
token model. This means that unless a user deliberately logs them out
of the app, or an admin inactivates or deletes their account, this
user will never have to re-authenticate after initial login. Instead,
the app/integration will refresh their tokens. Refreshing tokens does
not require stepping through the SSO login flow, while generating an
initial set of tokens does.
Changes in SSO status, whether between SSO Off, Enabled, and Required,
or between two different connections, have no effect on existing
authentication sessions. Users won't be forcibly logged out when SSO
is turned on.
Upon next login attempt will the new SSO flow come into play. In this case, these users were already authenticated into the integration
prior to SSO roll-out. The SSO change would have impacted behavior in
that these users would need to authenticate via SSO going forward;
however, due to the persistent authentication model, that "next login"
never actually happens, and these users can continue to refresh tokens
and retain access without ever being challenged to authenticate into
the IdP again.

Related

Separate authentication and authorization servers for SPA app

I have
UI (a single page app)
an external authentication server
my own authorization server
resource server (my own backend APIs)
Here's what I am trying to do
UI/User gets an AuthN token from the external authentication server.
UI sends the AuthN token to get the an AuthZ token from my own authorization server
UI uses the AuthZ token to retrieve data from the resource server
But the problem is I don't know if the user is still authenticated anymore because I stopped using the AuthN token from step 3. Should I use both tokens together? or somehow consolidate the 2 tokens into one? Hope to get some ideas from here. Thanks!!
COMPONENTS
This is the standard way of managing components:
UI makes an OpenID Connect redirect to the Authorization Server (AS)
AS makes a second OpenID Connect redirect to the authentication system. There could be more than one of these, eg Google, Facebook.
After user sign in the AS issues the same tokens for your UI and resource server, regardless of how the user signs in. The UI sends access tokens to the resource server which can authorize based on scopes and claims received.
Unless you have special reasons, do not use foreign tokens from authentication systems in your own applications. This is because you are not in a position to control their contents.
OPENID CONNECT RE-AUTHENTICATION MECHANISMS
The OpenID Connect prompt and max-age parameters can be used to control how frequently the user is prompted to re-authenticate, and the auth_time claim can be issued in ID tokens to inform the UI of the last authentication time.
For example your app could use access tokens that last 15 minutes. Whenever they expire you could send a request with a prompt-none parameter to see if the user is still authenticated. If not then you will receive a login_required response and you could then redirect the user to re-authenticate.
SINGLE LOGOUT
Knowing if the user is still authenticated suggests you need to know if they signed out in another app. OpenID Connect has four Single Logout Mechanisms that you should be aware of, and which may possibly work for your scenario.
This is a technical area that has never worked perfectly in any Single Sign On technology though. This may be because you do not control all apps, or because of technical limitations, eg Google may not inform the Authorization Server if the user signs out of Gmail.
SUMMARY
Your apps should only use the authorization server tokens. Use OIDC request parameters to control when the user must re-authenticate.

IdentityServer4 - Login via ADFS without logon prompt appearing

With the use of IdentityServer4 and the OIDC protocol, I've managed to get my SPA and my .net core web api authenticating against a sql server user store, as well as ADFS which is great. However, when the user first clicks the 'Continue with ADFS' button, the login prompt is shown asking the user for their credentials. My understanding was that with the use of openId connect and IdentityServer, we could add external identity providers such as ADFS to our IdentityServer application and if ADFS is chosen for login with the user already logged in to ADFS via their local machine, then the authentication would happen seamlessly without the need to input windows user credentials again. There are other steps in order to achieve this of course, like linking the ADFS UserId with our SQL Database User Id table, but overall my understanding was that this would be entirely possible.
After a user logs out from an ADFS login, the next time the user chooses to log back in with ADFS, the 'Challenge' method that is run within my IdentityServer application to initiate the redirect to ADFS often recognises that the user has already logged in recently and therefore just logs them right in without the need for their credentials again.
My question is - is it actually possible to avoid the initial login prompt altogether? Or will the browser insist that credentials are provided if the user hasn't logged into the application for a while?
It certainly is possible but it may involve specific browser config in ADFS and also may require your IDP to be in the intranet zone in Windows Internet settings.
Check out these articles:
https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/operations/configure-intranet-forms-based-authentication-for-devices-that-do-not-support-wia
https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/operations/configure-ad-fs-browser-wia

SAML between existing account and service provider

Background:
I have a basic user database with username(email) and password. The users are able to sign in to a website of mine with these credentials. From the website they get a link to different services they have access to, but with different username/passwords. So they click the link "Open My Service X" and they have to login with their service unique login credentials. I do have the users service login-username. So I can map local-user <=> service-user.
I want SSO between service X which has support for SAML and my website.
Question/Problem:
I want the users to login with their user/password in my database, then single sign on towards service X where service X has support for SAML. I don't want a user to be able to sign up for a new user account to my website using the SAML support in service X. The user must already have an account in my database.
So my question might be rather vague, but I'm having a hard time to grasp how this can be achieved?
I was thinking of letting my webapp become a SAML identity provider, so that the SSO request are transferred back to my webapp and verified for their service-user. Would that be correct approach?
You're on the right track with your SAML IdP. There are basically three parts involved. Your email database (the identities), your existing application front end and the remote services which support SAML. Usually it's SAML2 these days.
To get single sign-on (SSO) across your portfolio of apps (your own app and the remote services) you could install an IdP like the Shibboleth IdP and convert your app to use it instead of using email/password to login. That would take a fair amount of work as you'd have to convert your app into a SAML SP, just like the remote services.
An easier way might be to only use the IdP for SAML to the remote services and get the IdP to recognise that your users are already logged in with their email/password. Cookie? So the IdP should never display a login page as it would recognise your app's cookie and match that with a user in the database. It then releases SAML attributes to the remote service based on that user's information. That also covers your use case of not allowing account creation via SAML from a remote service.
That would mean you might end up with the following URLs:
https://yourapp.com/
https://yourapp.com/idp/
Your users login with the first URL as normal and the remote services use the second URL. That way your app cookie will be visible to the /idp endpoint but you'd need to write code to match that with a user in the database.

Is it possible to have SPA authentication without redirecting to an outside login page

I am currently developing an SPA application that connects to a bunch of webAPI's. These API require that the user is logged in, so I started digging into Openid Conect and OAuth2 examples, mostly using IdentityServer.
They all require, for SPA reasons, that the implicit grant should be used for retrieving access_tokens. Token refreshes are handled connecting to authentication server using hidden iframe.
What I understand from this approach o renewing your access_token is that, sessions is maintained at authentication service. Hidden iframe goes to the authentication server, sessions is still active, new access_token is provided.
All that looks good for me, except (for UX reasosn) the fact that my user needs to be redirected to authentication server page for providing credentials.
Isn't it possible to have my SPA application send credentials to authentication server, getting the access_token, and then do the refresh using the hidden iframe for silently renewing (we, obviously dont want the user to keep informing credentials every 15 minutes or every hour..).
If this is not acceptable for security reasons, could you please explain why?
Technically it is possible with "resource owner password flow", but in that model identity provider can not trust your application and will not create a session for your user (to use silent renew later on). Thus such non-interactive approach is not truly SSO. For 2019 the recommended flow for any web app such as Angular SPA is Code flow with PKCE extension, as described here or there.
EDIT:
Editing this answer to correctly reflect the requirement.
If the requirement is not to show authentication server page and use your own SPA, the only possible way to do it is using "Resource owner password flow" with the constraints mentioned in the previous answer
This is discouraged for two reasons:
Security - Will the SPA have the same security controls as the "Authentication server" has in handling passwords of the user. Right from collection to management of the user password (safely securing for future calls ?). This will massively impact the scope of SPA and it is one of the main reasons why people prefer federated logins (outsourcing login complexity to the third party - in your case authentications server)
Trust - How would you convince the user to handout the "authentication server" password to a relatively new SPA app. Imagine if Google / Facebook allows this pattern for a SPA to collect password instead of redirecting to the Google / Facebook login page. This is a recipe for disaster.
This is exactly what oidc-client-js library does. Have a look at automaticSilentRenew settings in their wiki page. Understandably this only works as long as the session at the authentication server is still active.

OpenID authentication and API access

OpenID authentication is inherently browser based. If I wanted to allow an OpenID user to authenticate against an API for use in alternative clients, is there an accepted best practice for that?
So if a user tried to log in with their OpenID into an iPhone app, for instance, how would that work? The only thing I can think of generating an API token of some sort for them and get the user to manually enter it somewhere. This approach is not user friendly.
This is the way sites like Basecamp work, but it still seems clunky to me.
The problem you're seeing is not unique to OpenID. Any password-less authentication scheme can have this problem. OAuth (http://oauth.net/) is a solution that is an open standard that is quickly gaining traction on a lot of web sites. It is totally independent of how the user authenticates, so their OpenID Provider does not need to support or even be aware that your site (the "service provider" in OAuth terms) is using OAuth. Your API client can be web based or even a local application!
The process would be something like this:
Roles:
the user: someone who has an account with your web site.
service provider: your web site, which has a programmatic API that requires some credential to access.
consumer: the client, whether web or local application, that needs access to the service provider's API.
Flow:
The user is at the consumer. He indicates he wants to access data at the service provider.
The user is either redirected (if the consumer is a web site) or a browser is popped up (if the consumer is a local app) and the user sees the service provider web site.
The user is either already logged into the Service Provider via a persistent cookie, or the user must first log into the Service Provider however that is done (OpenID in your case).
The Service Provider then asks the user: "Consumer (some consumer) wants access to your data (or our API, or whatever). Do you want to authorize this? (yes/no)
User confirms, and the browser window closes or is redirected back to the Consumer site.
Via some OAuth protocol magic, the consumer now has a secret credential that it can use to access your API and access whatever user-private information you just authorized.
Obviously I can't include the whole OAuth spec here, but you can see hopefully from the above that this should solve your problem. OAuth libraries exist to make adding support for it easy.
If you happen to be using ASP.NET, I suggest http://dotnetopenid.googlecode.com/ as it recently added OAuth support (v3.0 beta 1).
Neither OpenID nor OAuth define how a user authenticates. They define how the consumer directs the user agent to the authentication provider, how the user agent is directed back, and how the consumer can verify the identity that the user authenticated as.
The actual method used to authenticate is out of band for both schemes.
There are differences between OpenID and OAuth, but both require that the consumer use HTTP redirects and callback URLs. They're both browser based. If your app speaks HTTP, it can do either. However, a main point is that the user is only entering credentials into a trusted app.
What you want is not possible with OpenID. OpenID is based on the premise that you (the iPhone app) only want to know about your users that their OpenID-provider trusts them. They never authenticate themselves to you.
Good OpenID-providers in fact even prevent that you mediate the authentication process (as this would expose users to a possible attack - by you!): they demand that users login with them directly and refuse login-by-referral.
See: this related question
The problem is that the openid spec has no standard provision for authentication with the provider, so the provider can elect that authentication happens via a phone call or whatever.
Hopefully more providers embrace OAuth. Alternatively you could hand code the authentication for a few of the bigger sites.