简体   繁体   中英

oidcSecurityService checkAuth method returns false when authenticated with Identity Server

I am running an Angular (v9) app with Identity Server 4 and ADFS 3. In my app.component I am calling oidcSecurityService.checkAuth() which on arrival to the site, redirects to Identity Server and off to ADFS - there are two workflows

  • where the user enters a user/password for ADFS to authenticate and it returns back to Angular, all is authenticated (token is populated and.AspNetCore.Cookies is present)
  • where the ADFS login is automated and returns back to Angular via callback to Identity Server and a redirect to Angular - the.AspNetCore.Cookies is present but fails the oidcSecurityService.checkAuth(), because the token is null

My question is how is it that the Identity Server cookie is present and the token blank - I'm not sure of the sequence of how one exists without the other

Any ideas gratefully appreciated

UPDATE 1

A summary of the execution

app.component.ts

this.sub$ = this.oidcSecurityService
    .checkAuth()
    .subscribe((isAuthenticated) => {
        if (!isAuthenticated) {
            //navigate to route that executes oidcSecurityService.authorize();
            this.router.navigate(['/autologin']);
        }
    }

...this then gets sent to Identity Server 4 then to ADFS

Startup.cs as follows

services.AddAuthentication(sharedOptions =>
        {
            sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
        }
    )
    .AddWsFederation(options =>
    {
        options.MetadataAddress = "https://fed.my-adfs.com/federationmetadata/2007-06/federationmetadata.xml";
        options.Wtrealm = "https://auth.my-identity-server.com";
        options.SaveTokens = true;
        options.Events.OnRedirectToIdentityProvider = context =>
        {
            context.ProtocolMessage.Wct = DateTimeOffset.UtcNow.ToString();
            context.ProtocolMessage.Whr = "http://auth.header.com/IdSrv";
            context.ProtocolMessage.Wtrealm = "https://auth.my-identity-server.com";
            return Task.CompletedTask;
        };
    })
    .AddCookie(options =>
        {
            options.Cookie.Path = "/";
            options.Cookie.Name = ".AspNetCore.Cookies";
            options.Cookie.Expiration = new TimeSpan(DateTime.Now.AddHours(1).Ticks);

        }); 

request is sent to ADFS which responds with message to ExternalLogin

AccountController.cs

[HttpGet]
public async Task<IActionResult> ExternalLogin(string provider, string returnUrl)
{
    // start challenge and roundtrip the return URL and 
    var props = new AuthenticationProperties()
    {
        RedirectUri = Url.Action("ExternalLoginCallback"),
        Items =
        {
            { "returnUrl", returnUrl },
            { "scheme", provider },
        }
    };
    return Challenge(props, provider);
}

[HttpGet]
public async Task<IActionResult> ExternalLoginCallback()
{
    // read external identity from the temporary cookie
    //var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);
    var result = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    if (result?.Succeeded != true)
    {
        throw new Exception("External authentication error");
    }

    // lookup our user and external provider info
    var (user, provider, providerUserId, claims) = FindUserFromExternalProvider(result);
    if (user == null)
    {
        // this might be where you might initiate a custom workflow for user registration
        // in this sample we don't show how that would be done, as our sample implementation
        // simply auto-provisions new external user
        claims = result.Principal.Claims.ToList();

        //var userIdClaim = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Subject);
        //if (userIdClaim == null)
        //{
        //    userIdClaim = claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier);
        //}

        //if (userIdClaim == null)
        //    user = AutoProvisionUser(provider, providerUserId, claims);
        //else
        //    user = AutoProvisionUser(userIdClaim.Issuer, userIdClaim.Value, claims);
    }

    // this allows us to collect any additonal claims or properties
    // for the specific prtotocols used and store them in the local auth cookie.
    // this is typically used to store data needed for signout from those protocols.
    List<Claim> additionalLocalClaims = claims; //new List<Claim>();
    var localSignInProps = new AuthenticationProperties();
    //ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps);
    //ProcessLoginCallbackForWsFed(result, additionalLocalClaims, localSignInProps);
    //ProcessLoginCallbackForSaml2p(result, additionalLocalClaims, localSignInProps);

    // issue authentication cookie for user
    await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.SubjectId, user.Username));
    //await HttpContext.SignInAsync(user.SubjectId, user.Username, provider, localSignInProps, additionalLocalClaims.ToArray());
    // issue authentication cookie for user
    var identityServerUser = new IdentityServerUser(user.SubjectId)
    {
        DisplayName = user.Username,
        IdentityProvider = provider,
        AdditionalClaims = additionalLocalClaims
    };
    await HttpContext.SignInAsync(identityServerUser, result.Properties);

    // delete temporary cookie used during external authentication
    //await HttpContext.SignOutAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);
    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

    // validate return URL and redirect back to authorization endpoint or a local page
    var returnUrl = result.Properties.Items["returnUrl"];
    if (_interaction.IsValidReturnUrl(returnUrl) || Url.IsLocalUrl(returnUrl))
    {
        return Redirect(returnUrl);
    }

    return new RedirectResult(returnUrl);
}

With regards to the logs on the authorization server, these are quite verbose and as the issue is around what is happening client-side I'm not sure whether they provide further detail around the strategy - in other words I think the issue is more around the strategy mentioned above - ie although the above approach generates the required cookie, how does this translate into a token able to be checked by oidcSecurityService

UPDATE 2

(also added code to the ExternalLoginCallback method)

I am getting the following entry in my Identity Server logs

AuthenticationScheme: Identity.Application was successfully authenticated.

...However it seems when the code reaches ExternalLogin I'm getting

AuthenticationScheme: Identity.Application is not authenticated.

How is it that earlier in the workflow it was authenticated but then later it is not - hence when the ExternalLoginCallback code is executed it tries to authenticate the user against the ExternalCookieAuthenticationScheme as follows:-

var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

... this fails as the user is no longer authenticated

UPDATE 3

[14:23:56 DBG] Persisted Grants Request Options: Microsoft.Azure.Documents.Client.RequestOptions
[14:23:56 DBG] Ensure Persisted Grants (ID:PersistedGrants) collection exists...
[14:23:56 DBG] PersistedGrants Creation Results: OK
[14:23:56 INF] Executing action method MI.ParentReporting.AuthorizationServer.Controllers.AccountController.ExternalLoginCallback (MI.ParentReporting.AuthorizationServer) with arguments (null) - ModelState is Valid
[14:23:56 DBG] AuthenticationScheme: Cookies was successfully authenticated.
...
[14:23:56 INF] FindUserFromExternalProvider-claim-type: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
[14:23:56 INF] FindUserFromExternalProvider-claim-value: xxxxNamexxxx
[14:23:56 INF] FindUserFromExternalProvider-claim-type: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/applicationid
[14:23:56 INF] FindUserFromExternalProvider-claim-value: xxxxAppIdxxxx
[14:23:56 INF] FindUserFromExternalProvider-claim-type: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/applicationname
[14:23:56 INF] FindUserFromExternalProvider-claim-value: xxxxAppNamexxxx
[14:23:56 INF] FindUserFromExternalProvider-claim-type: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role
[14:23:56 INF] FindUserFromExternalProvider-claim-value: xxxxRolexxxx
[14:23:56 INF] FindUserFromExternalProvider-claim-type: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/username
[14:23:56 INF] FindUserFromExternalProvider-claim-value: xxxxUsernamexxxx
[14:23:56 INF] FindUserFromExternalProvider-claim-type: http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod
[14:23:56 INF] FindUserFromExternalProvider-claim-value: urn:oasis:names:tc:SAML:1.0:am:password
[14:23:56 INF] FindUserFromExternalProvider-claim-type: http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationinstant
[14:23:56 INF] FindUserFromExternalProvider-claim-value: 2020-08-16T14:23:49.956Z
[14:23:56 ERR] An unhandled exception has occurred: Unknown userid
System.Exception: Unknown userid
   at MI.ParentReporting.AuthorizationServer.Controllers.AccountController.FindUserFromExternalProvider(AuthenticateResult result) in c:\Builds\6\s\MI.ParentReporting.AuthorizationServer\Controllers\AccountController.cs:line 492
   at MI.ParentReporting.AuthorizationServer.Controllers.AccountController.ExternalLoginCallback() in c:\Builds\6\s\MI.ParentReporting.AuthorizationServer\Controllers\AccountController.cs:line 327
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.Invoke(HttpContext context)
   at IdentityServer4.Hosting.BaseUrlMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.Invoke(HttpContext context)
   at NWebsec.AspNetCore.Middleware.Middleware.MiddlewareBase.Invoke(HttpContext context)
   at NWebsec.AspNetCore.Middleware.Middleware.MiddlewareBase.Invoke(HttpContext context)
   at NWebsec.AspNetCore.Middleware.Middleware.MiddlewareBase.Invoke(HttpContext context)
   at NWebsec.AspNetCore.Middleware.Middleware.MiddlewareBase.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context)

UPDATE 4

The following is the token (wresult) returned by the call to idpinitiatedsignon (you'll notice the applicationid and userid claims are Guids)

<?xml version="1.0" encoding="UTF-8"?>
<trust:RequestSecurityTokenResponseCollection xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
   <trust:RequestSecurityTokenResponse Context="14a9edee-4545-6767-8989-f056689bbba9">
      <trust:Lifetime>
         <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2020-08-17T06:43:10.785Z</wsu:Created>
         <wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2020-08-17T07:43:10.785Z</wsu:Expires>
      </trust:Lifetime>
      <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
         <wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
            <wsa:Address>http://fed.my-adfs.com/adfs/services/trust</wsa:Address>
         </wsa:EndpointReference>
      </wsp:AppliesTo>
      <trust:RequestedSecurityToken>
         <Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="_d56a3e1b-4545-6767-8989-0412df22d292" IssueInstant="2020-08-17T06:43:10.785Z" Version="2.0">
            <Issuer>http://auth.header.com/IdSrv</Issuer>
            <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
               <SignedInfo>
                  <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                  <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
                  <Reference URI="#_d56a3e1b-4545-6767-8989-0412df22d292">
                     <Transforms>
                        <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                     </Transforms>
                     <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
                     <DigestValue>wzdbJxxxxxxxxxxxxxxxxxxxxxxxxxxxxxigSBSqq5c=</DigestValue>
                  </Reference>
               </SignedInfo>
               <SignatureValue>geh3N+ag846uxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkgV2gVrybPg==</SignatureValue>
               <KeyInfo>
                  <X509Data>
                     <X509Certificate>MIIIvTxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxG14YZl9</X509Certificate>
                  </X509Data>
               </KeyInfo>
            </Signature>
            <Subject>
               <NameID>xxxxMyNameIdxxxx</NameID>
               <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer" />
            </Subject>
            <Conditions NotBefore="2020-08-17T06:43:10.785Z" NotOnOrAfter="2020-08-17T07:43:10.785Z">
               <AudienceRestriction>
                  <Audience>http://fed.my-adfs.com/adfs/services/trust</Audience>
               </AudienceRestriction>
            </Conditions>
            <AttributeStatement>
               <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/username">
                  <AttributeValue>xxxxMyUserNamexxxx</AttributeValue>
               </Attribute>
               <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role">
                  <AttributeValue>xxxxMyRolexxxx</AttributeValue>
               </Attribute>
               <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/applicationid">
                  <AttributeValue>7df29e67-4545-6767-8989-4463eafca398</AttributeValue>
               </Attribute>
               <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/applicationname">
                  <AttributeValue>xxxxMyAppNamexxxx</AttributeValue>
               </Attribute>
               <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/userid">
                  <AttributeValue>5b00eedc-4545-6767-8989-c6586a377ffd</AttributeValue>
               </Attribute>
               <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/lastactivitydate">
                  <AttributeValue>8/17/2020 2:42:54 AM</AttributeValue>
               </Attribute>
               <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/profileid">
                  <AttributeValue>33333</AttributeValue>
               </Attribute>
               <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/sessiondatetime">
                  <AttributeValue>8/17/2020 2:42:54 AM</AttributeValue>
               </Attribute>
               <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/userfirstname">
                  <AttributeValue>xxxxMyFirstNamexxxx</AttributeValue>
               </Attribute>
               <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/userlastname">
                  <AttributeValue>xxxxMyLastNamexxxx</AttributeValue>
               </Attribute>
               <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name">
                  <AttributeValue>xxxxMyNamexxxx</AttributeValue>
               </Attribute>
            </AttributeStatement>
            <AuthnStatement AuthnInstant="2020-08-17T06:42:57.203Z">
               <AuthnContext>
                  <AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</AuthnContextClassRef>
               </AuthnContext>
            </AuthnStatement>
         </Assertion>
      </trust:RequestedSecurityToken>
      <trust:RequestedAttachedReference>
         <SecurityTokenReference xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:d4p1="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" d4p1:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0">
            <KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID">_d56a3e1b-4545-6767-8989-0412df22d292</KeyIdentifier>
         </SecurityTokenReference>
      </trust:RequestedAttachedReference>
      <trust:RequestedUnattachedReference>
         <SecurityTokenReference xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:d4p1="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" d4p1:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0">
            <KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID">_d56a3e1b-4545-6767-8989-0412df22d292</KeyIdentifier>
         </SecurityTokenReference>
      </trust:RequestedUnattachedReference>
      <trust:TokenType>urn:oasis:names:tc:SAML:2.0:assertion</trust:TokenType>
      <trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>
      <trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>
   </trust:RequestSecurityTokenResponse>
</trust:RequestSecurityTokenResponseCollection>

The following is the wresult back from the call to signin-wsfed (it looks like the applicationid claims has been translated while the userid claims has been dropped)

<?xml version="1.0" encoding="UTF-8"?>
<t:RequestSecurityTokenResponse xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
   <t:Lifetime>
      <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2020-08-17T06:43:11.046Z</wsu:Created>
      <wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2020-08-17T07:43:11.046Z</wsu:Expires>
   </t:Lifetime>
   <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
      <wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
         <wsa:Address>https://auth.my-identity-server.com</wsa:Address>
      </wsa:EndpointReference>
   </wsp:AppliesTo>
   <t:RequestedSecurityToken>
      <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" MajorVersion="1" MinorVersion="1" AssertionID="_42406433-4545-6767-8989-be94f93d551c" Issuer="http://fed.my-adfs.com/adfs/services/trust" IssueInstant="2020-08-17T06:43:11.061Z">
         <saml:Conditions NotBefore="2020-08-17T06:43:11.046Z" NotOnOrAfter="2020-08-17T07:43:11.046Z">
            <saml:AudienceRestrictionCondition>
               <saml:Audience>https://auth.my-identity-server.com</saml:Audience>
            </saml:AudienceRestrictionCondition>
         </saml:Conditions>
         <saml:AttributeStatement>
            <saml:Subject>
               <saml:SubjectConfirmation>
                  <saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod>
               </saml:SubjectConfirmation>
            </saml:Subject>
            <saml:Attribute xmlns:a="http://schemas.xmlsoap.org/ws/2009/09/identity/claims" AttributeName="name" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims" a:OriginalIssuer="http://auth.header.com/IdSrv">
               <saml:AttributeValue>xxxxMyNamexxxx</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute AttributeName="applicationid" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
               <saml:AttributeValue>xxxxMyAppIdxxxx</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute AttributeName="applicationname" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
               <saml:AttributeValue>xxxxMyAppNamexxxx</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute xmlns:a="http://schemas.xmlsoap.org/ws/2009/09/identity/claims" AttributeName="role" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims" a:OriginalIssuer="http://auth.header.com/IdSrv">
               <saml:AttributeValue>xxxxMyRolexxxx</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute xmlns:a="http://schemas.xmlsoap.org/ws/2009/09/identity/claims" AttributeName="username" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims" a:OriginalIssuer="http://auth.header.com/IdSrv">
               <saml:AttributeValue>xxxxMyUserNamexxxx</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute xmlns:a="http://schemas.xmlsoap.org/ws/2009/09/identity/claims" AttributeName="userlastname" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims" a:OriginalIssuer="http://auth.header.com/IdSrv">
               <saml:AttributeValue>xxxxMyFirstNamexxxx</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute xmlns:a="http://schemas.xmlsoap.org/ws/2009/09/identity/claims" AttributeName="userfirstname" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims" a:OriginalIssuer="http://auth.header.com/IdSrv">
               <saml:AttributeValue>xxxxMyLastNamexxxx</saml:AttributeValue>
            </saml:Attribute>
         </saml:AttributeStatement>
         <saml:AuthenticationStatement AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:password" AuthenticationInstant="2020-08-17T06:42:57.203Z">
            <saml:Subject>
               <saml:SubjectConfirmation>
                  <saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod>
               </saml:SubjectConfirmation>
            </saml:Subject>
         </saml:AuthenticationStatement>
         <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <ds:SignedInfo>
               <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
               <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
               <ds:Reference URI="#_42406433-4545-6767-8989-be94f93d551c">
                  <ds:Transforms>
                     <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                     <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                  </ds:Transforms>
                  <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
                  <ds:DigestValue>mwWAxixxxxxxxxxxxxxxxxxxxxxxxxxxxFAt7xen8VE=</ds:DigestValue>
               </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue>30xaIbQ9SxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxhINHESWbg==</ds:SignatureValue>
            <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
               <X509Data>
                  <X509Certificate>MIIC2jCCAcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxlMQB80pi/zJZeo=</X509Certificate>
               </X509Data>
            </KeyInfo>
         </ds:Signature>
      </saml:Assertion>
   </t:RequestedSecurityToken>
   <t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType>
   <t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
   <t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType>
</t:RequestSecurityTokenResponse>

I assume the "sub" (as well as sid, idp, etc) claims should be within these also - if so the end result of the configuration doesn't look like it is including these (sub, sid, idp, etc) - this is strange as I am picking up some claims such as "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod" and "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationinstant" as well as some properties like ".AuthScheme"

UPDATE 5

As mentioned above I have authenticated against ADFS and I have all of the custom claims I require - because I am missing some detail (sub, etc) I have created code in the ExternalLoginCallback around creating the new user with the required detail (a freshly generated subjectId and id_token)

[HttpGet]
public async Task<IActionResult> ExternalLoginCallback()
{
    var result = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    if (result?.Succeeded != true)
    {
        throw new Exception("External authentication error");
    }

    // lookup our user and external provider info
    var (user, provider, providerUserId, claims) = FindUserFromExternalProvider(result);
    if (user == null)
    {
        // this might be where you might initiate a custom workflow for user registration
        // in this sample we don't show how that would be done, as our sample implementation
        // simply auto-provisions new external user
        claims = result.Principal.Claims.ToList();

        var userIdClaim = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Subject);
        if (userIdClaim == null)
        {
            userIdClaim = claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier);
        }

        if (userIdClaim == null)
            user = AutoProvisionUser(provider, providerUserId, claims);
        else
            user = AutoProvisionUser(userIdClaim.Issuer, userIdClaim.Value, claims);
    }

    // this allows us to collect any additonal claims or properties
    // for the specific prtotocols used and store them in the local auth cookie.
    // this is typically used to store data needed for signout from those protocols.
    List<Claim> additionalLocalClaims = claims; //new List<Claim>();
    var localSignInProps = new AuthenticationProperties();
    ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps);
    //ProcessLoginCallbackForWsFed(result, additionalLocalClaims, localSignInProps);
    //ProcessLoginCallbackForSaml2p(result, additionalLocalClaims, localSignInProps);

    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("rlyaKithdrYVl6Z80ODU350md")); //Secret
    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

    var token = new JwtSecurityToken("https://auth.my-identity-server.com",
        "https://client.my-angular-application.com",
        claims,
        expires: DateTime.Now.AddMinutes(30),
        signingCredentials: creds);

    var generatedToken = new 
    {
        access_token = new JwtSecurityTokenHandler().WriteToken(token),
        expires_in = 600000,
        token_type = "bearer"
    };
    var id_token = JsonConvert.SerializeObject(generatedToken, new JsonSerializerSettings {Formatting = Formatting.Indented});
    localSignInProps.StoreTokens(new[] { new AuthenticationToken { Name = "id_token", Value = id_token } });

    //issue authentication cookie for user
    await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.SubjectId, user.Username));
    await HttpContext.SignInAsync(user.SubjectId, user.Username, provider, localSignInProps, additionalLocalClaims.ToArray());

    // delete temporary cookie used during external authentication
    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

    return new RedirectResult("https://client.my-angular-application.com/");
}

All runs successfully - I see all of the fields I have added to the new user and the new user is signed-in (I see the message in the Identity Server logs "AuthenticationScheme: Identity.Application signed in"). However when I redirect to my Angular (client) application I'm still not authenticating (using oidcSecurityService.checkAuth), (and as such cannot see claims, etc). I see the cookie in the Identity Server 4 website - I'm missing how this should be visible from within the Angular website when it authenticates

Any ideas greatly appreciated

In your ExternalLoginCallback method, are you not supposed to signin the external user with IdentityServer, so it can issue its own access token to the client(Angular?)

including code like

// issue authentication cookie for user
var isuser = new IdentityServerUser(user.SubjectId)
{
    DisplayName = user.Username,
    IdentityProvider = provider,
    AdditionalClaims = additionalLocalClaims
};

await HttpContext.SignInAsync(isuser, localSignInProps);

Otherwise, why do you just do a redirect in that method?

This was a fairly unusual case and mostly due to (as mentioned) some claims not showing up after authentication with ADFS (crucially the sub claim) - the problem after I auth'd against ADFS and created the Identity Server auth cookie was that the logic in the Identity Server ProfileService needed tweaking to firstly flag as active (change the search to look for username [which I was getting back] rather than sub) then when it got claims get the claims that were being populated in ExternalLoginCallback - mine was at the user level rather than the ClaimsPrincipal level

I must say it took me a while to understand the interaction between OidcSecurityService and IdentityServer4 and the additional edge case that I was dealing with ADFS 3 (as opposed to ADFS 4 which supports OpenId)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM