I'm looking for a bit of best-practice advice from someone a bit more knowledgeable than me in the Federated Security area.
Our Scenario
We host a (subscription) webservice (WCF/Asp.Net/IIS). We also have a purely JavaScript component (widget) that our customers embed within their intranet applications. The widget calls the webservices for data so therefore we need the widget to make cross-domain requests from their domain to our domain.
The widget currently does this using a combination of JsonP and Script Tag Injection approach to Ajax. (Reason - a combination of the age of the widget and continuing support for older non-CORS browsers).
The Problem
All of our customers require a Single-SignOn so their users are not asked to login to the widget. We have achieved this in until now by issuing an ApiKey to a new user and asking them to enter that into the widget on first use, and a cookie is then created for use thereafter.
We need to integrate Federated Authentication into this scenario. The webservice (on our domain) is the Relying Party (RP) and the widget (hosted on the customer domain) is the Client. The Identity Provider and STS would also be on the customer domain.
From my research so far I think I can make the following statements:
This scenario requires an Active Federation approach. Passive Federation is never used when the RP is a webservice.
We need to add Federated endpoints to our WCF service to allow an Active client to call us supplying a Saml token.
Making our widget an Active client that communicates with the webservie directly is not possible. This would require the Widget to request identity and pass it onto the RP. This would be too much for a JavaScript only app.
Possible Solutions
Is it actually up to the host page of the widget (aka. the customer's intranet application) to be the Client in the FedAuth scenario?
We could provide a proxy that would be hosted in the customer domain and act as the Active Client for our webservices RP. The widget could then be unaware of any authentication.
Are we missing something really obvious?
I would really appreciate a couple of words in comment on the above if you can help us out and can spare the time. I'd be happy to hear that my assertions are incorrect as well. All news is good news at this point...
We eventually found a workaround:
For customers who want Saml Authentication we host the widget component in our domain in a standalone webpage and they embed in their webpage using an iframe.
this approach achieves the appearance of widget integration within their site, although not as originally intended, and it allows us to leverage Passive authentication. The iframe behaves just like a normal browser in that respect and handles the handshake with the STS server.
This is less than ideal but we were unable to come up with anything better. It suits our customer's needs whilst maintaining security. That doesn't mean I have to like it though.
Related
I am looking into Azure Active Directory OpenIDConnect authentication alongside an ASP.NET application, all of the quickstarts work very well when dealing with a self-hosted application and I am able to login correctly following their guides.
As part of the work I am looking at, there is a requirement to load my application inside an IFrame hosted in another application which is not in my control. This parent application will take care of the authentication of the user, and the IFrame version of my application will be expected to be utilising the same sign-on to access its content.
I cannot seem to see documentation regarding this on MSDN, has anyone any experience in that kind of setup? Will it even work?
I believe the domain of my application would need to be a sub-domain of the parent hosting application for the purpose of cookies, but will my application have access to cookies that are present in the parent applications interaction because that's how I believe it would know there is a logged-in context?
Many thanks!
Trying to run an app on an iframe will be problematic because the Authorization Server will block requests via X-Frame-Options headers, which will be set to DENY by default.
If it was me I would tell stakeholders that using an iframe is a solution, not a requirement, and try to get to the underlying behaviour people are looking for.
These scenarios are often based around avoiding double logins, but sometimes a simple / standard solution such as this works best, and gets past all blocking issues and complexity:
User signs in to App A and provides a credential
User single signs on to App B very quickly
The standard option will be simple, future proof and extensible, whereas non standard options can add many hidden costs. If explained to stakeholders they may be happy with this type of solution.
IFRAME LOGINS
This is a matter of configuring the X-Frame-Options header to allow your web origin.It is a fairly common solution, but has potential security and portability issues.
Quite a few providers support iframe logins, but from Googling I suspect that Azure AD does not. If so then logins via popups are another option to consider.
COOKIES AND USER GESTURES
Another problem you are likely to run into is that browsers are increasingly dropping third party cookies these days. Using SSO cookies via full browser redirects works fine, but when issued via iframes and popups the browser is likely to drop them on subsequent requests.
PROOF OF CONCEPT
A good way forward is to develop a tiny app that uses Azure AD and iframes, to simulate your production setup. This should only take a few days and you can experiment with options until you find something that works and that your stakeholders are happy with.
I have an OpenID Connect provider built with IdentityServer4 and ASP.NET Identity, running on let's say: login.example.com.
I have a SPA application running on let's say spa.example.com, that already uses my OpenID Connect provider to authenticate users through login.example.com and authorize them to access the SPA.
I have a mobile app (native on both platforms) that is using a custom authentication system at the moment.
I thought it would be nice to get rid of the custom auth system, and instead allow my users to log-in with the same account they use on the SPA, by using my OpenID provider.
So I started by looking on the OpenID connect website and also re-reading the RFC6749, after a few google searches I realized that was a common problem and I found RFC8252 (OAuth2 for Native clients), also Client Dynamic Registration (RFC7591) and PKCE (RFC7636).
I scratched my head about the fact that it was no longer possible to store any kind of "secret" on the client/third-party (the native apps) as it could become compromised.
I disscussed the topic with some co-workers and we came out with the following set-up:
Associate a domain let's say app.example.com to my mobile app by using Apple Universal Links and Android App Links.
Use an AuthenticationCode flow for both clients and enforce them to use PKCE.
Use a redirect_uri on the app associated domain say: https://app.example.com/openid
Make the user always consent to log-in into the application after log-in, because neither iOS or Android would bring back the application by doing an automatic redirect, it has to be the user who manually clicks the universal/app link every time.
I used AppAuth library on both apps and everything is working just fine right now on test, but I'm wondering:
Do you think this is a secure way to prevent that anyone with the right skills could impersonate my apps or by any other means get unauthorized access to my APIs? What is the current best practice on achieving this?
Is there any way to avoid having the user to always "consent" (having them to actually tap the universal/app link).
I also noted that Facebook uses their application as a kind of authorization server itself, so when I tap "sing-in with facebook" on an application I get to a facebook page that asks me if I would like to" launch the application to perform log-in". I would like to know how can I achieve something like this, to allow my users login to the SPA on a phone by using my application if installed, as facebook does with theirs.
I thought it would be nice to get rid of the custom auth system, and instead allow my users to log-in with the same account they use on the SPA, by using my OpenID provider.
This is what OAuth 2.0 and OpenID Connect provides you. The ability to use single user identity among different services. So this is the correct approach .!
it was no longer possible to store any kind of "secret" on the client/third-party (the native apps) as it could become compromised
Correct. From OAuth 2.0 specification perspective, these are called public clients. They are not recommended to have client secrets associated to them. Instead, authorization code, application ID and Redirect URL is used to validate token request in identity provider. This makes authorization code a valuable secret.!
Associate a domain let's say app.example.com to my mobile app by using Apple Universal Links and Android App Links.
Not a mobile expert. But yes, custom URL domains are the way to handle redirect for OAuth and OpenID Connect.
Also usage of PKCE is the correct approach. Hence redirect occur in the browser (user agent) there can be malicious parties which can obtain the authorization code. PKCE avoid this by introducing a secret that will not get exposed to user agent (browser). Secret is only used in token request (direct HTTP communication) thus is secure.
Q1
Using authorization code flow with PKCE is a standard best practice recommended by OAuth specifications. This is valid for OpenID Connect as well (hence it's built on OAuth 2.0)
One thing to note is that, if you believe PKCE secret can be exploited, then it literally means device is compromised. Think about extracting secret from OS memory. that means system is compromised (virus/ keylogger or what ever we call them). In such case end user and your application has more things to be worried about.
Also, I believe this is for a business application. If that's the case your clients will definitely have security best practice guide for their devices. For example installation of virus guards and restrictions of application installation. To prevent attacks mentioned above, we will have to rely on such security establishments. OAuth 2.0 alone is not secure .! Thats's why there are best practice guides(RFC68129) and policies.
Q2
Not clear on this. Consent page is presented from Identity Provider. So it will be a configuration of that system.
Q3
Well, Identity Provider can maintain a SSO session in the browser. Login page is present on that browser. So most of the time, if app uses the same browser, users should be able to use SPA without a login.
The threat here comes from someone actually installing a malicious app on their device that could indeed impersonate your app. PKCE prevents another app from intercepting legitimate sign in requests initiated from your app so the standard approach is about as safe as you can make it. Forcing the user to sign in/consent every time should help a bit to make them take note of what is going on.
From a UX PoV I think it makes a lot of sense to minimize the occasions when the browser-based sign in flow is used. I'd leverage the security features of the platform (e.g. secure enclave on iOS) and keep a refresh token in there once the user has signed in interactively and then they can sign in using their PIN, finger print or face etc.
I have the following scenario:
1.- A web api project in Azure, that I want to secure using Azure AD (I don't mind Token, cookie, whatever, as far as it meets the entire scenario)
2.- An Azure web site in asp.net MVC, also secured by Azure AD. This website has to call the web api controller with SSO (I'm using same Azure AD in the entire scenario)
3.- Some JavaScript code running in a page in SharePoint Online, also calling the web api controller in any secure way (The Office 365 tenant is also using same Azure AD). If you don't know about SharePoint, let's say I have an SPA project where I can only use Javascript and html (no server side code).
Following some of the MS Azure AD samples and some blogs from Vittorio Bertocci I'm able to get the points 1 and 2 working fine, using OWIN and Oppen ID connect. However, seems impossible to achieve point 3. As I'm inside a page in SharePoint Online, I can only use javascript, and not any server side code. I'd like to get a valid token for the current user, that is already logged in SP, and remember that SP uses same Azure AD that web api site.
Can I call the Azure AD and get a valid token, just from client code?
I'm open to any possible solution. I can do whatever in the web api project. If you are thinking in a SharePoint app with an appPart, and the appPart calls the web api from server side code, I agree that will work, but it's an option that is not allowed at the moment :(
Many thanks.
I have similar needs. While waiting for a Microsoft sponsored solution we’re working on the following approach.
3) in Your solution (i.e. HTML page with JavaScript, hosted in SharePoint Online and running in Browser) will call Services in 1) (i.e. Web Api Service layer in Azure).
In Our case we only want to validate that the calls made from SharePoint Online (via users browser, i.e. JavaScript) originate from a correct Office 365 / SharePoint Online user in our tenant.
We are opting out of using the App Model as we only want some simple HTML / JavaScript pages in our Intranet and don’t want App Webs. The Web Api server side code is kind of our “Web Part” code behind.
Change to the solution after trying it out and having workable code:
The auth cookies are ReadOnly and cannot be used. Instead we have registered one metod in our service layer as App in SharePoint Online (via appregnew.aspx). That methods url (e.g. https://cloudservice.customer.com/api/authentication/token) is registered as App start page in the app manifest and is deployed to a site Collection.
Now we can call our App via https://customer.sharepoint.com/sites/devassets/_layouts/15/appredirect.aspx?instance_id={GUID} i a jQuery ajax call and parse the result. AppRedirect sends the correct SPAuthToken which we use in our service endpoint (i.e. App start page) to call back to SharePoint and check context.Web.CurrentUser. User email is then stored in Table Storage with a generated Token which we send back to the caller (i.e. the jQuery ajax call to app redirect).
That token is then used in all other service layer calls in order to be sure of who is calling our service layer and in some cases perform authorization in our service layer.
Note, You can use the same approach in order to store Refresh and AccessToken in your client and provide that in all calls to your service from your client and use those tokens in order to do App Calls back to SharePoint. This enables HTML UI in SharePoint host webs and server code using user context in Azure service layer.
To follow up, ADAL.js has recently been released, and the ability to use CORS with O365 APIs was recently added, enabling a scenario for script clients to communicate with services protected by Azure AD, such as your Web API.
http://www.andrewconnell.com/blog/adal-js-cors-with-o365-apis-files-sharepoint
UPDATE 2018:
This is now supported by SharePoint Online and the SPFx development model, and officially documented, for instance here
Consume enterprise APIs secured with Azure AD in SharePoint Framework
Being said that the work done meanwhile by Vittorio, Kirk, and their teams, but extending that also to Andrew that has delivered great samples, is awesome; that doesn't really fully reply the original question because one of the requirements is to don't run the component as Add-in Part.
If you try to use ADAL JS (which starts its own OAuth flow) hosting that directly in a SP page, that's not going to work, or anyway you can expect a weird behavior for the user (cause of client redirects happening on the browser).
The solution proposed by Peter Karpinski is interesting, and will work matching the requirements in the original question, but requires quite some complexity and additional management/resources.
This recent article provides an alternative solution similar to Peter's one, but requiring less 'extras' and somewhat simpler, also reusing user's SP identity.
Consuming Azure Hosted Web API from SharePoint Online using JavaScript and Office 365 identities
and doesn't either require the use of ADAL on the client side and the implementation of custom security provider / token issuer on the server side.
The identity (cookie) will be passed via properly handling CORS (documentation) on both sides.
However, as you can read in my comments to that blog, this won't work normally with IE due to its security zone implementation. You'll have to be sure you have control on IE security zones on the clients, or have an alternative solution specific for IE.
As of today AAD does not support the OAuth2 implicit flow (or OpenId Connect variants) hence you can't obtain a token from AAD using a user-agent (browser), regardless of whether you hit the wire handcrafting the protocol or using a library.
However keep an eye on future announcements, as this is an important scenario for us!
HTH
Cheers,
V.
update we now support the implicit flow on our server, and we released a library for helping you consume the new feature: http://www.cloudidentity.com/blog/2015/02/19/introducing-adal-js-v1/
Thank youi for r your patience!
The fact that you say you can use only HTML/JS let me guess you're having a SharePoint-hosted App.
Azure AD Authentication Library (ADAL) doesn't provide yet in this moment support for HTML5.
I've been looking since a while (almost one year) on how to implement something as you say; but I couldn't find any working solution, which doesn't make use also of some 'code-behind'.
I'd suggest you then to move to a Provider-hosted App, where you'll be able to have some C# code, and make use of ADAL to retrieve and reuse the OAuth token.
Also, I think is worth to look at this documentation page:
Choose patterns for developing and hosting your app for SharePoint
at section Match your hosting pattern with your development goals
thanks for your help.
Well, it's not a SP-Hosted App, but it's same scenario. It's just a SP page in SP Online, so I can only use JS code like in a SP-hosted app.
As I said in my question, I agree the Provider hosted app is likely the right (or at least, the unique) solution, but that means to build and app, deploy it, and add teh appPart manually to the page (is not easy to package in a WSP). So, this solution is quite hard, when you only want to make some AJAX calls and show some data.
However, after all that I've seen, I think we can't do anything else. I'm gonna wait some more days to see if someone know any weird workarround that could work, and if not, I'll mark your answer as valid.
Thanks again!
Looking for a pointer in the right direction ...
Is there a mechanism which allows you to configure SharePoint in such a way that:
if a user has been successfully authenticated within a SharePoint site that there is some kind of "authentication token" what can be passed or is available to 3rd party sites
or a way for 3rd party sites to "recognize" that the user is currently authenticated within a sharepoint environment
all 3rd party apps can be modified to accommodate whatever needs to be done
but the constraint is: SharePoint may or may not be a hosted (by a separate service provider) and how the original authentication took place is irrelevant i.e. just need to know they authenticated ok, not how
EDIT
scenario to help clarify:
authenticated SP users require access to a 3rd party service provider for additional content. a "link" on their SP site redirects through to the 3rd party. the 3rd party needs to recognize the referrer (based on a collection of evidence supplied by the request) so that it need not challenge for a secondary authentication process.
one of the 3rd parties is me. the SP instances are many and varied and would be any one of my clients (which i don't offer support to, just provide a content service to).
so the attempt is to solve more of a general "community/ecosystem" problem.
Going on the small amount of information available here.... You are probably going to use Windows Authentication (via Active Directory) or Forms based authentication.
If you are using AD within your organization and the other server you are authenticating to is using the same AD, it's a no brainer. If it's AD based but both servers are using different domains, it's much more complex. One option would be to setup a trusted share between the ADs.
If you are using Forms Based authentication it becomes a bit more of an issue. If both servers are using the same FBA, you could create the authentication cookie in SharePoint and then add the cookie as a header to a Request object and then redirect to the server.
If they are different authentication methods totally, you need to determine if your security requirements will allow users to authenticate via some URL based mechanism (like querystrings) and then develop the logic on your SP box to create the URL to authentication.
Your requirements are a little vuage but this should point you in the right direction.
Plan authentication methods (SharePoint Server 2010)
Specifically Claims based authentication.
I'm guessing that by "3rd party sites" you mean sites that aren't hosted in your domain. If that's the case, then the servers won't be able to use your AD authentication (unless you share them, which probably isn't worth it).
I would suggest modifying the way users are authenticated on the 3rd party servers, as you have control over how you send your users over there. You could easily encrypt their usernames/emails/unique IDs and a timestamp (to make sure they can't bookmark that link) in a query string.
The information is then decrypted on the 3rd party server. Invalid information and they are redirected to your login page. Valid information and the 3rd knows that they were authenticated in your sharepoint app.
Your question is very confusing.
SharePoint may or may not be a hosted
What do you mean by that?
Are you invoking a 3rd party web app from a SharePoint page? You can get the current user using SPWeb.CurrentUser property and make use of it.
We have one web application (sharepoint) that collects information from disparate sources. We would like to be able to link users to the main websites of those various sources and have them pre-authenticated. I.E. they enter their credentials for the other sources (which are a number of different types LDAP, AD and home grown!) and we retrieve some information for them, and remember there details (Possibly Single Sign-on to keep em nice and safe). The user can then click a link that will open the full app in another window already authenticated.
Is this even likely to be possible?
Office Server has a Single-Sign-On api as a builtin feature. you may want to look into that. It enables you to register user credentials securely, and to access it at runtime.
You need to act as a web browser acts to different sites with storing credentials (usually in cookies) locally. Use therefore a a proper client library with cookie support. This could go probably for most of sites. There are sites using HTTP authentication, which are also easier to access from appropriate client libraries. The most demanding can be access to SSL websites, but again, most client HTTP libraries cover that nowadays as well.
All you need now is just to prepare your web application to act as a proxy to all those separate web resources. How exactly this is done in Sharepoint, well, I hope others will answer that...
True Single Sign-on is a big task. Wikipedia describes common methods and links to a few SSO projects.
If you want something lighter, I've used this approach in the past:
Create a table to store temporary security tokens somewhere that all apps can access.
From the source app (Sharepoint in your case), on request of an external app, save a security token (maybe a guid, tight expiration, and userid) in the token table.
Redirect to a request broker page/handler in the destination app. Include the final page requested and the guid in the request.
In the broker, look up the security token. If it exists and hasn't expired, authenticate, authorize, and redirect to the final page if everything is good. If not, send a permissions err.
Security-wise, a guid should be near impossible to guess. You can shrink risk by letting the tokens expire very quickly - it shouldn't take more than a few seconds to call the broker.
If the destination app uses Windows Auth and doesn't have role-based logic, you shouldn't have to do much. Just redirect and let your File/UrlAuthorization handle it. You can handle role-based permissions with the security token db if required.