Sustainsys / Saml2

Saml2 Authentication services for ASP.NET
Other
960 stars 602 forks source link

Using Okta as IdP within IdentityServer3 v2 #304

Closed dahlsailrunner closed 9 years ago

dahlsailrunner commented 9 years ago

Hi - I'm trying to get Okta (a SAML-based corporate SSO provider) configured as an IdP configured in IdentityServer3 using the Kentor.AuthServices (and Owin).

My code is as follows:

var authServicesOptions = new KentorAuthServicesAuthenticationOptions(false)
{
            SPOptions = new SPOptions
            {
                EntityId = new EntityId(my audience value from okta)
            },
            SignInAsAuthenticationType = signInAsType,
            AuthenticationType = "okta",
            Caption = "Okta",
        };

        authServicesOptions.IdentityProviders.Add(new IdentityProvider(
            new EntityId(metadataaddressfromokta)
            authServicesOptions.SPOptions)
            {
                LoadMetadata = true,
            });

        app.UseKentorAuthServicesAuthentication(authServicesOptions);            

The problem is almost certainly in the way I've got things configured, but I'm not sure where the problem is. The SPOptions Entityid is the value I have set for the "audience" within my developer instance at Okta. The Metadata address in the IdentityProvider constructor is the metadata address which I got from the okta config page.

The detailed error is shown below.

Any insight is greatly appreciated. Thanks - Erik

Unexpected entity id "http://www.okta.com/exk4yxtgy7ZzSDp8e0h7" found when loading metadata for "https://MyOktaInstance.oktapreview.com/app/exk4yxtgy7ZzSDp8e0h7/sso/saml/metadata". Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Configuration.ConfigurationErrorsException: Unexpected entity id "http://www.okta.com/exk4yxtgy7ZzSDp8e0h7" found when loading metadata for "https://MyOktaInstance.oktapreview.com/app/exk4yxtgy7ZzSDp8e0h7/sso/saml/metadata".

Source Error:

Line 82: }; Line 83: Line 84: authServicesOptions.IdentityProviders.Add(new IdentityProvider( Line 85: new EntityId("https://MyOktaInstance.oktapreview.com/app/exk4yxtgy7ZzSDp8e0h7/sso/saml/metadata"), Line 86: authServicesOptions.SPOptions)

AndersAbel commented 9 years ago

The metadata contains the entity id of the IDP. What the error message tries to say (I should probably update it) is that you've specified an Idp with entity id "https://MyOktaInstance.oktapreview.com/app/exk4yxtgy7ZzSDp8e0h7/sso/saml/metadata" in the configuration, but when loading the metadata, the entity id in the metadata is "http://www.okta.com/exk4yxtgy7ZzSDp8e0h7" .

To get it working:

AndersAbel commented 9 years ago

Please see also issue #305 which is a proposed improvement to make this situation less likely to occur.

dahlsailrunner commented 9 years ago

Ok that seemed to get me by the original hurdle.

My hurdle now is getting back into the Identity Server in my custom user service to set up my own identity with custom claims. I'm sure I've just configured something wrong. I keep getting a 404 when hitting my "login with okta" link.

I think the error is in the way I've configured Okta in some way.

The error with abbreviated stack trace is at the bottom of the message. The full (real) metadata address is here: https://dev-490944.oktapreview.com/app/exk4yxtgy7ZzSDp8e0h7/sso/saml/metadata

I've looked at the metadata and tried the SSO url and it seems to work when I go there directly: (https://dev-490944.oktapreview.com/app/nwpservicescorporationdev490944_satnwpidentity_1/exk4yxtgy7ZzSDp8e0h7/sso/saml)

I should note that my real goal is to get back into my custom user service within Identity Server to the AuthenticateExternalAsync with a real identity -- it seems like I need the SAML ACS endpoint configured for this but am not sure. If you can look at any of the included information and provide some guidance on a) how to eliminate the 404 problem shown in the error below b) how to make configure things to get back into my IdentityServer user service

I would really appreciate it. Code and error follow. Thanks in advance for your support and help. Sorry for the trouble. -Erik

var authServicesOptions = new KentorAuthServicesAuthenticationOptions(false)
{
            SPOptions = new SPOptions
            {

                EntityId = new EntityId("https://dev-490944.oktapreview.com/app/exk4yxtgy7ZzSDp8e0h7/sso/saml/metadata")
            },
            SignInAsAuthenticationType = signInAsType,
            AuthenticationType = "okta",
            Caption = "Okta",
        };

        authServicesOptions.IdentityProviders.Add(new IdentityProvider(
            new EntityId("http://www.okta.com/exk4yxtgy7ZzSDp8e0h7"),
            authServicesOptions.SPOptions)
            {
                LoadMetadata = true,
            });

        app.UseKentorAuthServicesAuthentication(authServicesOptions);          

Server Error in '/' Application.

The remote server returned an error: (404) Not Found. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Net.WebException: The remote server returned an error: (404) Not Found.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:

[WebException: The remote server returned an error: (404) Not Found.] System.Net.WebClient.OpenRead(Uri address) +548 Kentor.AuthServices.Metadata.MetadataLoader.Load(Uri metadataUrl) +84 Kentor.AuthServices.Metadata.MetadataLoader.LoadIdp(Uri metadataUrl) +30 Kentor.AuthServices.IdentityProvider.DoLoadMetadata() +210 Kentor.AuthServices.IdentityProvider.ReloadMetadataIfRequired() +171 Kentor.AuthServices.IdentityProvider.CreateAuthenticateRequest(Uri returnUrl, AuthServicesUrls authServicesUrls, Object relayData) +65 Kentor.AuthServices.WebSso.SignInCommand.CreateResult(EntityId idpEntityId, String returnPath, HttpRequestData request, IOptions options, Object relayData) +342 Kentor.AuthServices.Owin.d__7.MoveNext() +772

AndersAbel commented 9 years ago

That error message is because AuthServices cannot download the metadata from the given URL. The new configuration looks wrong. I might have been a bit unclear in my previous comment. Try this code:

var authServicesOptions = new KentorAuthServicesAuthenticationOptions(false)
{
    SPOptions = new SPOptions
    {
        EntityId = new EntityId(my audience value from okta)
    },
    SignInAsAuthenticationType = signInAsType,
    AuthenticationType = "okta",
    Caption = "Okta",
};

authServicesOptions.IdentityProviders.Add(new IdentityProvider(
    new EntityId("http://www.okta.com/exk4yxtgy7ZzSDp8e0h7"), authServicesOptions.SPOptions)
    {
        LoadMetadata = true,
        MetadataUrl = "https://dev-490944.oktapreview.com/app/exk4yxtgy7ZzSDp8e0h7/sso/saml/metadata"
    });

app.UseKentorAuthServicesAuthentication(authServicesOptions);
dahlsailrunner commented 9 years ago

Better!! I got to the login screen now, and then got a 400 bad request after properly signing in at okta. This may be because my local id server is not web-accessible. I'll keep at it and update my results here. If successful, it may help others in going down this path.

Again, really appreciate the help!

Takk saa mye! :)

dahlsailrunner commented 9 years ago

Hi Anders -- Just wondering if you have any ideas about my latest issue. I make my auth request to IdSever, it sends me to Okta and I'm able to login, but then I get an error from Id Server. I think the error is related to my configuration of the "ACS endpoint for my app" that I specified at Okta. I've set it as Id Srv's "connect/authorize" endpoint, but I keep getting a 405 Method not allowed. (HTTP content below).

I'm guessing I need to specify something other than the authorize endpoint, or enable the method somehow (I don't think it's CORS, but could be wrong).

Do you have any thoughts?
Much appreciated - Erik

POST https://iddev.nwpsmart.com/identity/connect/authorize HTTP/1.1 Host: iddev.nwpsmart.com User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: https://dev-490944.oktapreview.com/app/nwpservicescorporationdev490944_satnwpidentity_1/exk4yxtgy7ZzSDp8e0h7/sso/saml?SAMLRequest=fZHLbsIwEEX3SPxD5D1xXkBiAVJUNkh0A20XbJBJnGJBbNcz4dGvrxNALZsuPZ5z586dCfD6GBmWN7hXK%2FHVCEDvUh8VsNvPlDRWMc1BAlO8FsCwYOv8dckiP2DGatSFPpK%2FzP8IBxAWpVbEW8ynRJaj8ajiRcnLNIuSuMp2mYiLasTDIN5VaTIk3oew4IApcbyjABqxUIBcoSsF4XAQZIMofgsjFqYsCTbEm7s1pOLYUXtEA4zSUpwGSRZkSeLrA3JjxUmKs1%2FomnJjqDob5%2BwkCwGFtkbbDnfQjdkCR9ciS6FQ4nUbUnE5JNcLfl7Hm%2B%2F13KQi2I8pgKZtCsTLH4u%2BaAVNLez6pv6%2BWv56kqUb4Leja26x8%2FKYQNub3BmgeQFk1u953qTLmHUp2Fmr42S4kc7es077cCvc1Sb0iev37oXn089%2BAA%3D%3D&fromLogin=true Cookie: SignInMessage.ad5dd12a50d39341509377abe5c01db8=OdP0M1TOyQrFVGjDEQIqyUzNoPtDrr2DmAVNkxSjDsUS6LghM_AlbAvnqc6OP0sBDzpi3x81Y-Da7IJf-kj5xLhn8NUJ7b3xbNuBnGV5uTcySCsnw5X39LuZKeiKF9AunTZ-i3YPAL-0kLft7kkV7mPDOX2NwUYX1f6BtAt0aYjRB5BZ2XVItzpXoBjc-CDLr0XVJP5FJsDvtt3JufmoyZV5t8BD89ksP2lf-NnweMdpibPFPLGGKBlIdEdEO7gqOT6fLUKDEA_38M75YmW49QIGP0Zl5lcHuKHuZ3zxwhFeM5PBx7ZT0DMBV00UBQRDZ1Doht_8ADQrh0-kCjos1nYXTs3sLc3O8hZi8j-zlVN8fg1Nzrb1Mu2uLUmSZrVOiXStjz3cr55bz_Y8jRraB_a1Qu2OPeRIFRgjvCoyPww2_kzGKoavre2ZNkt2U0UTi32VeP4knGRzMzyszuYaydWLktMTa5qgZwShf3dnRNSWTr_tQMJW1KLUOSHEjz3vfh-uLgt3A-79IhyGi9GkyrxrCMmZpTQxU6nSgM7AgYmMDAyu2bS4dqs4Rnd7Nqbjw1RsjS2yqMRYkdw85xDEUqHI_dGBj9poBn0cnJAva7pqOiIt5rs212fS7K_btxGiL33VBw6b68DgpuB4YOSH5g Content-Type: application/x-www-form-urlencoded Content-Length: 9345

HTTP/?.? 405 Method Not Allowed Allow: GET Content-Length: 73 Content-Type: application/json; charset=utf-8 Server: Microsoft-IIS/10.0 X-Powered-By: ASP.NET Date: Wed, 23 Sep 2015 12:18:52 GMT X-Firefox-Spdy: h2

AndersAbel commented 9 years ago

The ACS endpoint should be ~/AuthServices/Acs, that is the AuthServices endpoint that consumes SAML assertions, not the IdSrv endpoint for the protocols IdSrv supports natively.

dahlsailrunner commented 9 years ago

Sweet! One last question. To get the SAML auth to work I had to add this line: Options.GlobalEnableSha256XmlSignatures(); This add was based on the output of an exception thrown by the Kentor stuff.

But then I get the exception below from IdentityServer3 when trying to return the identity to the actual application.

Do you have any insight as to what my revised Id Server config should be when doing this? Thanks a TON for all of your help. -Erik

Message: Exception:System.Security.Cryptography.CryptographicException Message: Invalid algorithm specified.

 HResult : -2146893816
 Source:mscorlib
 StackTrace: at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr) 

at System.Security.Cryptography.Utils.SignValue(SafeKeyHandle hKey, Int32 keyNumber, Int32 calgKey, Int32 calgHash, Byte[] hash, Int32 cbHash, ObjectHandleOnStack retSignature) at System.Security.Cryptography.Utils.SignValue(SafeKeyHandle hKey, Int32 keyNumber, Int32 calgKey, Int32 calgHash, Byte[] hash) at System.Security.Cryptography.RSACryptoServiceProvider.SignHash(Byte[] rgbHash, Int32 calgHash) at System.IdentityModel.Tokens.JwtSecurityTokenHandler.CreateSignature(String inputString, SecurityKey key, String algorithm, SignatureProvider signatureProvider) in c:\workspace\WilsonForDotNet45Release\src\System.IdentityModel.Tokens.Jwt\JwtSecurityTokenHandler.cs:line 854 at System.IdentityModel.Tokens.JwtSecurityTokenHandler.WriteToken(SecurityToken token) in c:\workspace\WilsonForDotNet45Release\src\System.IdentityModel.Tokens.Jwt\JwtSecurityTokenHandler.cs:line 815 at IdentityServer3.Core.Services.Default.DefaultTokenSigningService.CreateJsonWebToken(Token token, SigningCredentials credentials) in c:\ballen\github\identity\IdSrv3\IdentityServer3\source\Core\Services\Default\DefaultTokenSigningService.cs:line 91 at IdentityServer3.Core.Services.Default.DefaultTokenSigningService.SignTokenAsync(Token token) in c:\ballen\github\identity\IdSrv3\IdentityServer3\source\Core\Services\Default\DefaultTokenSigningService.cs:line 55 at IdentityServer3.Core.Services.Default.DefaultTokenService.d__c.MoveNext() in c:\ballen\github\identity\IdSrv3\IdentityServer3\source\Core\Services\Default\DefaultTokenService.cs:line 193

dahlsailrunner commented 9 years ago

Hi Anders (or whoever can review) --

I came across this item in the Id Svr repo: https://github.com/IdentityServer/IdentityServer3/issues/1903

Is there some kind of change that will be made within Kentor to address this or should I start going down the path of getting a different signing cert as noted in the final entry of the above thread?

Thanks in advance - Erik

ianhorton commented 9 years ago

Hi @dahlsailrunner

I had this same issue, I overcame it by configuring my app in Okta to use RSA_SHA1 for the Signature Algorithm in the SAML Settings. You can then remove the Options.GlobalEnableSha256XmlSignatures(); call from your Startup class, Idsrv is then able to create the JWT successfully.

HTH

Ian

dahlsailrunner commented 9 years ago

AWESOME!!! Thanks a lot Ian. This worked like a champ. The whole cycle is now working with Okta. Thanks for the suggestion and guidance. -Erik

albinsunnanbo commented 9 years ago

Great that you got it working. I think it would be super helpful if you could summarize the rather lengthy thread with a short step by step instruction to get Okta working with Authservices. @AndersAbel might have some input on where the documentation should be placed best. One suggestion is a new file ./doc/Compatibility.md, linked from ./README.md

dahlsailrunner commented 9 years ago

Would be happy to do this. I've not contributed to a project before but am eager to try. I'm thinking the process is for me to fork this repo, make my contributions, commit them, and then submit a pull request. Does that sound correct? If so, I'll try to get this done in the next couple of days.

albinsunnanbo commented 9 years ago

After fork, create a branch before adding your contributions. Pull requests from master gets messy, since pull requests are "live" tracking of the branch you make a pull request from. I assume you have read https://github.com/KentorIT/authservices/blob/master/CONTRIBUTING.md although most of it is not relevant when contributing documentation.

dahlsailrunner commented 9 years ago

pull submitted! :)

gaurav2ks commented 8 years ago

Hi Anders

Could you please share the details of the documentation?

I have a pretty much the similar scenario where i want to setup the following flow

Thanks & Regards Gaurav

++++++++++++++++++++++++++ Update : I found the link

https://github.com/KentorIT/authservices/blob/master/doc/IdentityServer3Okta.md

myaesubi commented 7 years ago

@dahlsailrunner, Hi Erik, This is an old thread, but I have similar issue though I followed the documentation.

Appreciate any hint https://github.com/KentorIT/authservices/issues/774

Thanks a lot, Mamrez

dahlsailrunner commented 7 years ago

Probably need more info -- what does your code look like and your okta config look like?

myaesubi commented 7 years ago

Thanks. As I'm really stuck on this for couple of days, I would really really appreciate any help!!

@albinsunnanbo @dahlsailrunner @AndersAbel .

I have detailed out the code and logs in the #774. I'm using AspNetIdentityUserService implementation of IdentityServer3 which uses ASP.NET Identity database as identity provider. This class as you might know already is implementing IUserService.

Implemented the "AuthenticateExternalAsync" override in the same class to create 'AuthenticateResult' and pass it on. now 'AuthenticateExternalAsync' is never called as I don't see any logs.

 public class CustomUserService : AspNetIdentityUserService<ApplicationUser, int>
    {
        IOwinContext ctx;
        public CustomUserService(ApplicationUserManager userMgr, OwinEnvironmentService env)
            : base(userMgr)
        {
            ctx = new OwinContext(env.Environment);
        }

        public override Task AuthenticateExternalAsync(ExternalAuthenticationContext ctx)
        {
            Log.Debug(String.Format("AuthenticateExternalAsync was hit with the provider id:{0} and Provider:{1}" , ctx.ExternalIdentity.ProviderId,ctx.ExternalIdentity.Provider));

            //ctx.ExternalIdentity.
            var nameClaim = ctx.ExternalIdentity.Claims.FirstOrDefault(c => c.Type == "name");
            var userName = nameClaim != null ? nameClaim.Value : "";
            try
            {

                Log.Debug("Username passed from Okta:" + userName);

                var user = userManager.FindByNameAsync(userName);

                ctx.AuthenticateResult = new AuthenticateResult(user.Id.ToString(), userName, ctx.ExternalIdentity.Claims);
            }
            catch(Exception e)
            {
                Log.Debug(String.Format("Exception happened: {0}",e.Message));
            }
            return Task.FromResult(0);
        }
}

Thanks again, Mamrez