简体   繁体   English

oidcSecurityService checkAuth 方法在使用 Identity Server 进行身份验证时返回 false

[英]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我正在使用 Identity Server 4 和 ADFS 3 运行 Angular (v9) 应用程序。在我的 app.component 中,我调用 oidcSecurityService.checkAuth() ,它在到达站点时重定向到 Identity Server 并关闭到 ADFS - 有两个工作流

  • 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)用户输入 ADFS 的用户/密码进行身份验证,然后返回 Angular,所有内容都经过身份验证(填充令牌并且存在.AspNetCore.Cookies)
  • 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 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我的问题是身份服务器 cookie 是如何存在而令牌为空白的 - 我不确定一个没有另一个的存在的顺序

Any ideas gratefully appreciated任何想法都将不胜感激

UPDATE 1更新 1

A summary of the execution执行摘要

app.component.ts 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 ...然后将其发送到 Identity Server 4,然后再发送到 ADFS

Startup.cs as follows Startup.cs如下

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请求被发送到 ADFS,ADFS 以消息响应 ExternalLogin

AccountController.cs 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关于授权服务器上的日志,这些非常冗长,因为问题在于客户端正在发生的事情,我不确定它们是否提供有关策略的更多细节 - 换句话说,我认为问题更多的是上面提到的策略 - 即虽然上述方法生成了所需的 cookie,但这如何转化为 oidcSecurityService 能够检查的令牌

UPDATE 2更新 2

(also added code to the ExternalLoginCallback method) (还在 ExternalLoginCallback 方法中添加了代码)

I am getting the following entry in my Identity Server logs我在身份服务器日志中收到以下条目

AuthenticationScheme: Identity.Application was successfully authenticated. AuthenticationScheme:Identity.Application 已成功通过身份验证。

...However it seems when the code reaches ExternalLogin I'm getting ...但是,当代码到达 ExternalLogin 时,我得到了

AuthenticationScheme: Identity.Application is not authenticated. AuthenticationScheme:Identity.Application 未通过身份验证。

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:-它是如何在工作流程的早期通过身份验证但后来却不是 - 因此,当执行 ExternalLoginCallback 代码时,它会尝试根据 ExternalCookieAuthenticationScheme 对用户进行身份验证,如下所示:-

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

... this fails as the user is no longer authenticated ...这失败了,因为用户不再经过身份验证

UPDATE 3更新 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更新 4

The following is the token (wresult) returned by the call to idpinitiatedsignon (you'll notice the applicationid and userid claims are Guids)以下是对 idpinitiatedsignon 的调用返回的令牌(wresult)(您会注意到 applicationid 和 userid 声明是 Guid)

<?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)以下是对 signin-wsfed 的调用返回的结果(看起来 applicationid 声明已被翻译,而 userid 声明已被删除)

<?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"我假设“sub”(以及 sid、idp 等)声明也应该在这些声明中 - 如果是这样,配置的最终结果看起来不像包括这些(sub、sid、idp 等) -这很奇怪,因为我收到了一些声明,例如“http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod”和“http://schemas.microsoft.com/ws/2008” /06/identity/claims/authenticationinstant”以及一些属性,如“.AuthScheme”

UPDATE 5更新 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)如上所述,我已经针对 ADFS 进行了身份验证,并且我拥有我需要的所有自定义声明 - 因为我缺少一些细节(子等)我在 ExternalLoginCallback 中创建了代码,围绕创建具有所需细节的新用户(新生成的subjectId 和 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").全部成功运行 - 我看到我添加到新用户的所有字段并且新用户已登录(我在 Identity Server 日志中看到消息“AuthenticationScheme:Identity.Application 已登录”)。 However when I redirect to my Angular (client) application I'm still not authenticating (using oidcSecurityService.checkAuth), (and as such cannot see claims, etc).但是,当我重定向到我的 Angular(客户端)应用程序时,我仍然没有进行身份验证(使用 oidcSecurityService.checkAuth),(因此看不到声明等)。 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我在 Identity Server 4 网站中看到了 cookie - 我错过了在 Angular 网站进行身份验证时应该如何看到它

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?)在您的 ExternalLoginCallback 方法中,您不应该使用 IdentityServer 登录外部用户,因此它可以向客户端(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这是一个相当不寻常的案例,主要是由于(如前所述)一些声明在使用 ADFS 进行身份验证后没有出现(至关重要的是 sub 声明) - 在我针对 ADFS 进行身份验证并创建身份服务器身份验证 cookie 之后的问题是逻辑在 Identity Server ProfileService 中需要调整以首先将其标记为活动(更改搜索以查找用户名 [我正在返回] 而不是子用户名),然后当它获得声明时,获取正在填充到 ExternalLoginCallback 中的声明 - 我的在用户级别而不是 ClaimsPrincipal 级别

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)我必须说我花了一段时间才了解 OidcSecurityService 和 IdentityServer4 之间的交互以及我处理 ADFS 3(而不是支持 OpenId 的 ADFS 4)的其他边缘情况

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 Jasmine 对 OidcSecurityService.checkAuth 功能进行单元测试? - How to unit testing OidcSecurityService.checkAuth function with Jasmine? isTokenExpired 方法返回 true 和 false - isTokenExpired method returns true and false Angular 11 - 模态方法检查数组中的值并返回 false,即使构造函数加载了数组 - Angular 11 - Modal Method checks for value in array and returns false even when the constructor loads the array 在 Angular 库中创建时,instanceof 返回 false - instanceof returns false when created in Angular Library 为什么angular导航时返回false - Why does the angular returns false when navigating 当canActivate返回false时,如何重定向另一个组件? - How to redirect another component when canActivate returns false? 如何使用 jasmine 对 OidcSecurityService.Auth() 进行单元测试? - How to unit test OidcSecurityService.Auth() with jasmine? Public get从auth服务返回一个权限布尔值,该权限布尔值初始化为false,并在NGRX存储返回值但未定义时进行修改 - Public get returns a permission boolean from auth service, which is initialized to false and modified when NGRX store returns a value but is UNDEFINED Angular 8 Observable返回“ _isScalar:false…” - Angular 8 Observable Returns “_isScalar:false…” 为什么切换复选框返回 false? - Why toggle checkbox returns false?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM