1

我正在尝试构建基于组件空间 SAML 解决方案的 IdP-Proxy。

到目前为止,我能够通过以下方式处理单点登录:

  1. 添加一个从SingleSignOnService接收AUTHN请求并向合作伙伴( )SP发起请求的方法。SSOIdPSP-initiated SSO
  2. 添加一个AssertionConsumerService正在接收SSO结果并检查IsInResponseTo标志的。根据这个标志,我确定了我是在流动中SP-initiated SSO还是在IdP-initiated SSO流动中,并相应地完成了流动。

我正在尝试使用以下示例流程以相同的方式处理单次注销:单一 SAMLv2 身份提供者代理注销

理论上,对于 SP 发起的注销,我需要实现以下目标: 1. 接收单个注销请求 2. 检查它是否不是响应 3. 识别 IdP 4. 向步骤 3 识别的 IdP 发送 Slo 请求 5 . 响应 SP 发起的 SLO 指示成功注销。

public async Task<IActionResult> SingleLogoutService()
{
    // Receive the single logout request or response.
    // If a request is received then single logout is being initiated by a partner service provider.
    // If a response is received then this is in response to single logout having been initiated by the identity provider.
    var sloResult = await _samlIdentityProvider.ReceiveSloAsync();

    if (sloResult.IsResponse)
    {     
    }
    else
    {
      // Figure out IdP Partner Name 
      var idpPartnerName = _configuration["IdPPartnerName"];

      // Send logout request to idp partner
      await _samlServiceProvider.InitiateSloAsync(idpPartnerName, sloResult.LogoutReason, sloResult.RelayState);

      // Respond to the SP-initiated SLO request indicating successful logout.
      await _samlIdentityProvider.SendSloAsync();
    }

    return new EmptyResult();
  }

我可以在 SP 结束时销毁会话,但我无法删除 IdP 会话(我在想

await _samlServiceProvider.InitiateSloAsync(idpPartnerName, sloResult.LogoutReason, sloResult.RelayState);

需要触发 IdP 会话删除,这是附加代理过程中的第三步)。

我缺少“协议方面”的东西吗?

附件(InitiateSloAsync方法):

public async Task InitiateSloAsync(string partnerName, string logoutReason, string relayState)
    {
      int num;
      if ((uint) num <= 5U)
        ;
      try
      {
        this.logger.LogDebug("Initiating SLO to the partner identity provider" + (string.IsNullOrEmpty(partnerName) ? "." : string.Format(" {0}.", (object) partnerName)), Array.Empty<object>());
        await this.LoadSamlStateAsync();
        this.LogSessionState();
        await this.GetLocalSpConfigurationAsync();
        if (this.SamlState.ServiceProviderSessionState.PendingResponseState != null)
          this.logger.LogDebug(string.Format("The pending SAML action {0} is being overridden.", (object) this.SamlState.ServiceProviderSessionState.PendingResponseState.Action), Array.Empty<object>());
        if (string.IsNullOrEmpty(partnerName) && this.SamlState.ServiceProviderSessionState.SsoSessions.Count == 1)
        {
          IEnumerator<SsoSessionState> enumerator = this.SamlState.ServiceProviderSessionState.SsoSessions.Values.GetEnumerator();
          enumerator.MoveNext();
          partnerName = enumerator.Current.PartnerName;
          enumerator = (IEnumerator<SsoSessionState>) null;
        }
        await this.GetPartnerIdpConfigurationAsync(partnerName);
        if (this.partnerIdentityProviderConfiguration.DisableOutboundLogout)
          throw new SamlProtocolException(string.Format("Logout to the partner identity provider {0} is disabled.", (object) partnerName));
        XmlElement xmlElement = await this.CreateLogoutRequestAsync(logoutReason);
        XmlElement logoutRequestElement = xmlElement;
        xmlElement = (XmlElement) null;
        await this.SendLogoutRequestAsync(logoutRequestElement, relayState);
        this.SamlState.ServiceProviderSessionState.SsoSessions.Remove(this.partnerIdentityProviderConfiguration.Name);
        SamlSubject.OnLogoutRequestSent(partnerName, logoutRequestElement, relayState);
        await this.SaveSamlStateAsync();
        this.LogSessionState();
        this.logger.LogDebug(string.Format("Initiation of SLO to the partner identity provider {0} has completed successfully.", (object) partnerName), Array.Empty<object>());
        logoutRequestElement = (XmlElement) null;
      }
      catch (Exception ex)
      {
        this.logger.LogError((EventId) 101, ex, string.Format("Initiation of SLO to the partner identity provider {0} has failed.", (object) partnerName), Array.Empty<object>());
        throw;
      }
    }
4

1 回答 1

1

根据此处列出的 ComponentSpace 响应:https ://www.componentspace.com/Forums/8806/?Update= 1#bm8813 问题与不等待 IdP 的响应有关。

根据当前的实现InitiateSloAsync,只会向 IdP 发送 SLO 请求,但不会等待响应。

// Send logout request to idp partner
await _samlServiceProvider.InitiateSloAsync(idpPartnerName, sloResult.LogoutReason, sloResult.RelayState);

// Respond to the SP-initiated SLO request indicating successful logout.
await _samlIdentityProvider.SendSloAsync();

过程如下:

  1. 接收来自 SP 的注销请求。
  2. 识别 IdP。
  3. 向 IdP 发送注销请求。
  4. 接收来自 IdP 的注销响应。
  5. 向 SP 发送注销响应。

重要提示:在充当身份提供者与服务提供者时,使用不同的单一注销服务端点可能是有意义的。

当您充当 IdP 时:

public async Task<IActionResult> SingleLogoutService()
{
  // Receive the single logout request or response.
  // If a request is received then single logout is being initiated by a partner service provider.
  // If a response is received then this is in response to single logout having been initiated by the identity provider.
  var sloResult = await _samlIdentityProvider.ReceiveSloAsync();

  if (sloResult.IsResponse)
  {   
  }
  else
  {
    // Figure out IdP Partner Name 
    var idpPartnerName = _configuration["IdPPartnerName"];

    // Send logout request to idp partner
    await _samlServiceProvider.InitiateSloAsync(idpPartnerName, sloResult.LogoutReason, sloResult.RelayState);
  }

  return new EmptyResult();
}

当您担任 SP 时:

public async Task<IActionResult> SingleLogoutService()
{
  // Receive the single logout request or response.
  // If a request is received then single logout is being initiated by the identity provider.
  // If a response is received then this is in response to single logout having been initiated by the service provider.
  var sloResult = await _samlServiceProvider.ReceiveSloAsync();

  if (sloResult.IsResponse)
  {
    // Respond to the SP-initiated SLO request indicating successful logout.
    await _samlIdentityProvider.SendSloAsync();  
  }
  else
  {
  }

  return new EmptyResult();
}

PS:如果您最终创建了两个不同的端点来处理注销,请不要忘记更新您的SingleLogoutServiceUrl属性。

于 2018-05-24T09:03:36.743 回答