Search code examples
asp.net-coresamlokta

User authentication in Asp.Net Core 3 with Saml2 and Okta as Service Provider


I'm replacing our in-house invented authentication service with Okta and need to support SSO with Saml2 into our application. Okta can be configured as Service Provider, send SAMLRequest and receive and validate SAMLResponse. So far so good: I was able to configure Identity Provider in Okta, receive the assertion and, according to logs, the assertion was successfully validated and user auto provisioned.

But what happens from now?

  1. In Idp initiated flow how can I redirect the user to application url? Is RelayState configured by Idp is only the option? I don't like the idea that all our clients will have to make a change if we change our app url. I'd expect the possibility to link the Idp to Okta application, so the redirect url will be configured by this application.
  2. After redirecting to our application site, how do I authenticate the user in Asp.Net Core? I implemented custom AuthenticationHandler that reads sid cookie that was set by Okta on redirect and retrieve the session information from Okta. From there I get user name and create Principal. This approach works but looks me wrong - it's too manual, I'd expect Okta.Sdk to do that for me (if this is correct way for authentication).
  3. After successful assertion validation is it possible to exchange saml token to OAuth token for authentication in application?

Solution

  • Answers to your questions based on pure SAML approach:

    1. You can use SP-initiated SSO - you'll achieve the same goal of landing on some page. Let's say your application acting as a SAML service provider resides at my.app.com and you want the users to land on https://my.app.com/foo/bar after they're authenticated. Publishing https://my.app.com/foo/bar to your clients/users will result in SP-init flow being kicked off when they eventually click on this link. After some back-and-forth between IdP and SP, the user will land on https://my.app.com/foo/bar as their final destination.

    You can implement the same idea with IdP-initiated flow via an additional redirect in your app or upstream of your app in your stack. This is sometimes called a vanity URL. For example, if the vanity URL is https://my.app.com/home, your app or another upstream component can translate this URL to another, target URL and issue a redirect to the target. The target URL can kick off an IdP-initiated flow with RelayState or a SP-initiated flow as described above. Your app or upstream component has to maintain the mapping between vanity and target URLs.

    1. You want Okta to be your SAML identity provider and your application to be the SAML service provider. You tried this cookie-based workaround because you didn't understand how to implement SAML in your .NET app.

    Okta does not provide a SAML toolkit or SDK for .NET apps acting as SAML service providers, they recommend 3rd party libraries. ASP.NET doesn't support SAML out of the box...which is another reason Okta recommends 3rd parties. (Microsoft is not one of these 3rd parties). Two popular, free and widely used choices are Sustainsys and ITFoxTec. Have a look at their docs, pick one and implement it. You shouldn't have to resort to your cookie workaround after that.

    1. After the SAML response is processed by your application and the reply (if any) is generated, the authentication step is done and the identity of a principal is known. Your application can now do whatever you want as a next step, including acquiring an oAuth token. This next step is not part of SAML protocol...unless it's a fresh/new SAML flow, that is.

    Answers to your questions based on the approach where you use Okta as the SAML service provider and identity store with another SAML identity provider. The flow is 2 hops: SAML IdP -> Okta as a SAML SP -> your app.

    Your app has to integrate with Okta via front-channel callback (SAML-like) or API callback (oAuth-like). The latter more or less requires the former although there are lots of variations in this path. The answers below assume a front-end callback style of integration.

    1. Your app will be "invoked" via RelayState by having Okta redirect to the URL in RelayState after it processes the SAML response from the first hop. If you make your RelayState be https://my.app.com/foo/bar, then after some back-and-forth between IdP and SP and your app, the user will land on https://my.app.com/foo/bar as their final destination. Your app will have to trigger this sequence by activating the 1st hop via either IdP-initiated or SP-initiated SAML flow.

    2. In a front-end callback style of integration, you'll be using Microsoft interfaces + Okta libs as shown in Okta's example.

    3. With Okta as your identity store and an authenticated principal, you can get tokens from Okta via additional steps. If your goal is to enable API calls into your app from a 3rd party via Okta, look into API callback style of integration.