I am trying to have users silently authenticated using Microsoft Azure AD OAuth2. I am calling this url in an IFrame for my online website:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?prompt=none&response_type=code&client_id=XXXXX-XXX&scope=openid profile offline_access User.ReadBasic.All
If the user is logged in this works perfectly on all browsers and returns the authorization code.
However for domain joined machines this does not work for IE & Edge, but does on Chrome..?
For IE & Edge the authorize page returns error=interaction_required. When the prompt=none is removed however from the url and called in a new browser tab it authenticates without any interaction though..
Why do IE & Edge require interaction on domain joined machines, when it apparently does not need it and Chrome works completely fine?
An educated guess is that this behavior is enforced to avoid delivering tokens to applications without the user explicitly being aware of it. iframe-based applications differ from a regular web applications because the former have inherently more security risks associated with them in the form of click-jacking https://en.wikipedia.org/wiki/Clickjacking.
Related
I can't help but think I've implemented Open ID slightly incorrectly, but I also cannot find why I've done the implementation the way I have is bad or not.
Scenario:
Website - Used forms authentication before being updated to use OWIN. Forms auth has been stripped out.
Website now supports OpenId to Okta. This is being implemented for a large company of our users to facilitate their logins. This is functional.
The method I use for the site models how Microsoft does logins. On email domain detection, we redirect the user to the login page for their domain. In this case, Okta. We receive the callback, and look up the user in our existing data, and generate a cookie based on our existing data (or create a new user account if they don't have one).
Essentially, just using Okta to confirm they are a valid user, and then we log them in with our user data. We foresee doing this for other companies as well.
Problem:
I have a desktop (WPF) client that requires a login to our website. This talks to API's that already exist using an auth key/token system we built many years ago. Ideally, we do something similar. Use Okta to verify the user is a user of that system, then generate a token that can be used for these API's.
Here is where I'm not sure I've done this appropriately.
The desktop client calls an API endpoint on our site with the email domain the user entered. We verify the user's domain is allowed to use SSO, and if so, we issue back a challenge endpoint for the client to call. This challenge endpoint is then called by the desktop client to launch the users default browser.
This challenge endpoint is an endpoint on OUR website, that essentially triggers the challenge to the IdP. After login, a callback is called on OUR website, to process the auth response. We verify the user's account is valid, and get the refresh token from the response. With the refresh token, and an identifier of the user, this data is then sent back to the desktop client using localhost:randomPort so the client can consume the refresh token and identitifer. (Note that I do encrypt the refresh token and identifier's before returning them to the client)
This refresh token is then POSTed to OUR website, along with their identifier (so we can identify the IdP we should call), then use an OIDC client to verify the refresh token is still valid. If the refresh token is still valid, we generate an app token and return it.
Is there a glaring issue with how this is implemented that I'm not seeing? How can I do this differently?
You seem to be missing the role of an Authorization Server (AS) that you own, to manage connections to other systems and to issue tokens to your apps.
You seem to have some good separation and to be doing quite a few things well - eg you are using your own tokens rather than foreign Okta tokens. The main issue is likely to be growing the system.
PREFERRED BEHAVIOUR
An AS should result in simpler code and a system that is easier to extend:
You can add new authentication methods quickly
This should involve just adding a connection (eg Okta) to your AS
Doing so requires zero code changes in your UIs and APIs
Your UIs just use standard OpenID Connect flows and call AS endpoints, regardless of the authentication method used
Your APIs just verify tokens issued by the AS, then authorize requests, regardless of the authentication method used
Some scripting is needed in the AS, but typically this is small.
FEATURES
In terms of what an AS should do for you, have a browse of the Curity Concepts Pages. I work there, and we try to write about the science of OAuth and the common extensibility features software companies need.
CHOOSING YOUR MOMENTS
Integrating an AS and getting past all the blocking issues is a gradual journey though, and involves learning. So it requires choosing your moments, spikes and getting buy in from your stakeholders.
The main objective should always be simple and standard code in your apps, that is easy to scale. OAuth and the Authorization Server give you design patterns that help with this.
All OAutt Authorization code flow examples I've seen sends the user to a specific login page provided by the IDP Server (Identity Provider Server).
https://auth0.com/docs/flows/authorization-code-flow-with-proof-key-for-code-exchange-pkce
I'm wondering can the login page be on the client itself, as in through an APP or SPA? Or is this something unsecure which I am not aware off. Thank
Usually it is standard to redirect as you say, but security also depends on the credential being used:
If a user is signing in via their Google password then your app should definitely never see the credentials and you should always redirect
If the user is signed in via a password stored at Company X, to only access data stored at Company X, and the password is not used for any other purposes, then it is less bad, since the company owns all of the assets involved
People who avoid redirecting usually end up using a deprecated flow such as Resource Owner Password Grant. I would avoid that, since it will not fare well in security reviews and restricts your future authentication options.
To be on the safe side I would recommend sticking to the redirect model, and using a login method provided by the Identity Management System vendor.
FUTURE DIRECTION
Interestingly, there is an emerging trend from some vendors to remain within the app when that makes sense. See the Hypermedia Authentication API, which may become a standard. A key characteristic of this is that the Authorization Server continues to govern security and tell the app what to do.
Is opening a browser to display a login page, which was generated from the site performing the authentication, built into the OAuth2 specification?
My requirements and constraints are going to prevent me from having a browser on the device. However, a request to authenticate the user against Azure Active Directory has been made. They are really looking for the desktop application to have fields in its own GUI for the username and password, and the ability to check if that's a registered user or not.
Is opening a browser to display a login page, which was generated from the site performing the authentication, built into the OAuth2 specification?
It is related to used OAuth2 flow specification, not to OAuth2 specification.
My requirements and constraints are going to prevent me from having a browser on the device.
That means you can't follow RFC8252 (where that browser is required).
So your only option is Resource Owner Flow/Direct Access Grant. But it isn't "secure", because app will have access to user credentials. Other cons: single sign-on won't be working, some IDPs may have also problem with multi factor authentication for this flow and security enterprise departments also don't like this flow at all usually.
I have a SPA App (VueJS) which uses Azure B2C with MSAL to authenticate users. Authentication works just fine.
But what does not work is, that the user is not kept logged in.
As long as i use the app, everything works just fine. But when i start my app the next day i have to relogin (or just reselect the account I want to use), but I would like to have the same user experience like for example the azure portal. I can revisit the portal after one week and do not have to relogin.
How can i achieve this behavior with MSAL? Is this even possible with this library? The library uses the implicit flow.
Is there another library i can use where this works?
Generally, browser-based applications shouldn't keep users logged in, since activity, such as a password change or reset, at the identity provider can invalidate a persistent session and should force an interactive login.
You should consider the "keep me signed in (KMSI)" capability that has been enabled for custom policies.
Before the answer...
I think you'll likely need to expand on what's happening by looking at a network tracing tool. Also, as the other answer said, KMSI will help but likely isn't the only problem here. I recommend looking if the cookie is being set (check below), your app is successfully getting ID, Access tokens, and check this state in subsequent auth requests.
Basics
SSO with MSAL.js is absolutely possible and should occur without much configuration. For some background in browser-based apps implementing authentication, achieving SSO is a factor of cookies/sessions rather than tokens/token management.
How this works
When your single page app redirects the user to the Azure AD B2C sign in page and the end user successfully signs in, Azure AD will set a cookie in the browser of that end user. Then, when your app wants to get an ID token or Access token for the user (assuming the existing one from the initial sign in is expired), MSAL is able to launch a silent i-frame in the background, redirect to the Azure AD site with special query parameters (prompt=none), and utilize the cookie that was set earlier.
Currently we are not using OAuth with our apps but we are working on making the shift, we have direct login and capture the user/pass that was entered and store those. We then turn around and use the stored credentials for a feature that allows the user to open a record within Salesforce.com, we pass the user/pass in to the login endpoint along with a starting URL to the specific record, this works great and is a well liked feature as it is a simple SSO from the App to Salesforce.com where the user can see all data that may not be visible within the app.
Moving to OAuth 2.0 and using the standard webflow, we no longer can capture the user/pass, which is actually a good thing as far as security is concerned. We would however like to keep this functionality, is there anyway of SSO'ing into Salesforce.com by passing along one of the OAuth tokens or some kind of sesson id?
After reading more and thinking about what OAuth accomplishes I feel like this probably isn't possible being that the tokens obtained are meant to be used only with the API and not with the front end system. I hope that I am wrong though and there is a way to login to the front end using these tokens.
EDIT
Ok I am editing to hopefully make this more clear. Currently user's authenticate using the login() API method with their user/pass, we store this user/pass locally (not ideal). We then sync a subset of data that the users can access anytime within the app, being that it is a subset, we have a feature to "SSO" to the Salesforce.com front-end. This simply opens Salesforce.com in a web-view (UIWebView) using the URL https://ns8.salesforce.com/?pw=PASSWORD&un=username#example.com&startURL=/recordId. This will log us in to Salesforce.com and open the specified record.
Moving forward we want to use OAuth 2.0 with the web flow so that we aren't handling the user/pass and so that we do not have to deal with Security Tokens or opening specific IP ranges to allow login without a Security Token.
With that said, is there anyway to use the tokens/credentials received from the OAuth authentication to open Salesforce.com, automatically log the user in, and goto a specific record?
I may have mis-used "single sign on" before, but in a sense, this simulates an SSO from our App to Salesforce.com, in that our users can touch a single button within the app and be logged in to the Salesforce.com web interface.
When you request an OAuth token, you can specify what scope it has, options include api only (the original type of tokens), or other options which include the ability to use the token with the UI pages. (see the scope parameter detail in the help). One of the still missing peices is a way to bootstrap the UI with that token when all you can do is tell a browser/webview to goto a URL, but a widely used (but unsupported) way is via frontdoor.jsp, e.g. you'd open https://{instance}/secur/frontdoor.jsp?sid={the_Access_token}&retURL={optional_relative_url_to_open} remember to URLEncode the 2 values.
So I think you are saying your application uses the SFDC username and password to just authenticate to retrieve a record from SFDC to display in your app?
IF this is correct - which I think it is - then you could just use the standard Salesforce Single Sign On system to authenticate. There is a guide here which outlines the process of setting up a SAML SSO system with Pat Patterson writing an interesting feature on how the security system works here. He has also written a great blog post on DeveloperForce here about the nitty details of OAuth in general for Force.com and not just the SAML setup. I have used the OAuth system in an iPad app against SFDC and it works quickly and easily. I can't see why your system should be unable to use the protocol as you desire.
Direct access into Salesforce is a key benefit of SSO and definitely provided. I'm not sure where you read that SSO in Salesforce is API only. From the SSO PDF pbattisson linked for you:
With single sign-on, users only need to memorize a single password to
access both network resources or external applications and Salesforce.
When accessing Salesforce from inside the corporate network, users are
logged in seamlessly, without being prompted to enter a username or
password. When accessing Salesforce from outside the corporate
network, users' corporate network login works to log them in. With
fewer passwords to manage, system administrators receive fewer
requests to reset forgotten passwords.
OAuth 1 & 2 are both supported, though I'm a fan of OAuth 2 since 1 has really finicky additional steps involving the order of parameters and their encoding sequences. I recently wrote an Apex-Twitter integration and quickly realized it wasn't going to be as easy as Facebook, which uses OAuth 2.0.
But in your case it sounds like you just want to provide users with the ability to actually login to Salesforce and go to a specific landing page once authenticated. This is definitely doable.
Good luck!