ComponentSpace

Forums



Determine SAML Request Type with ISamlIdentityProvider


Determine SAML Request Type with ISamlIdentityProvider

Author
Message
doering
doering
New Member
New Member (7 reputation)New Member (7 reputation)New Member (7 reputation)New Member (7 reputation)New Member (7 reputation)New Member (7 reputation)New Member (7 reputation)New Member (7 reputation)New Member (7 reputation)

Group: Forum Members
Posts: 5, Visits: 7
We need a method for our Identity Provider to determine if the received SAML request is an sign-on or a logout request.
Currently we're using the ReceiveSsoAsync() and ReceiveSloAsnyc() methods. Unfortunately the methods throw an exception, if the message wasn't the right type (SSO or SLO).

To solve this, we implemented these extension methods, which return null instead of an exception.


public static class SamlProviderExtensions
{
  private const string SamlMessageParseError =
   "A SAML message cannot be received as the HTTP request is unrecognized.";

  public static async Task<IdpSsoResult> TryReceiveSsoAsync(this ISamlIdentityProvider samlIdentityProvider)
  {
   try
   {
        return await samlIdentityProvider.ReceiveSsoAsync();
   }
   catch (Exception ex) when (ex.Message == SamlMessageParseError)
   {
        return null;
   }
  }

  public static async Task<SloResult> TryReceiveSloAsync(this ISamlIdentityProvider samlIdentityProvider)
  {
   try
   {
        return await samlIdentityProvider.ReceiveSloAsync();
   }
   catch (Exception ex) when (ex.Message == SamlMessageParseError)
   {
        return null;
   }
  }
}


This workaround around isn't very safe. Furthermore each time the methods throw an exception, they also do log an extra error message, which spams our logfiles.

Please, can you add such kind of methods to your API to allow pre-checking SAML requests.

Thanks in advance

ComponentSpace
ComponentSpace
ComponentSpace Development
ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)

Group: Administrators
Posts: 3.2K, Visits: 11K
Our recommendation is to use separate endpoints to receive SAML authn requests vs SAML logout messages.
That way you have separate methods to handle SSO vs SLO rather than handling both in the one method.
Is there a reason you wish to use the same endpoint for both SSO and SLO?

Regards
ComponentSpace Development
doering
doering
New Member
New Member (7 reputation)New Member (7 reputation)New Member (7 reputation)New Member (7 reputation)New Member (7 reputation)New Member (7 reputation)New Member (7 reputation)New Member (7 reputation)New Member (7 reputation)

Group: Forum Members
Posts: 5, Visits: 7

We're using IdentityServer for SSO with OpenID Connect and ourselves added support for WS-Federation (using the implementation of Dominick Baier: https://github.com/IdentityServer/IdentityServer4.WsFederation) and SAML (using the ComponentSpace library). The WS-Federation implementation by default has one endpoint for SSO and SLO. So we wanted the same for SAML to keep it consistent.

Another reason is that we've previously had for years ADFS. ADFS by default is using the same endpoint for SSO and SLO. So we have a lot of SAML Clients that are used to have one endpoint for SSO and SLO. Some of our clients experienced problems with their configuration if the endpoints differ.

The classes from the System.IdentityModel namespace have a method to determine the message type (SSO or SLO). Please can you support us with implementing the same behavior for SAML?


if (WSFederationMessage.TryCreateFromUri(new Uri(url), out WSFederationMessage message))
{
    if (message is SignInRequestMessage signin)
    {
        return await ProcessSignInAsync(signin);
    }

    if (message is SignOutRequestMessage signout)
    {
        return ProcessSignOutAsync(signout);
    }
}



ComponentSpace
ComponentSpace
ComponentSpace Development
ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)

Group: Administrators
Posts: 3.2K, Visits: 11K
Our recommendation to use separate endpoints still stands.
However, we'll look into whether there's an efficient way to support this.
Please contact us at [email protected].

Regards
ComponentSpace Development
cooke
cooke
New Member
New Member (1 reputation)New Member (1 reputation)New Member (1 reputation)New Member (1 reputation)New Member (1 reputation)New Member (1 reputation)New Member (1 reputation)New Member (1 reputation)New Member (1 reputation)

Group: Forum Members
Posts: 1, Visits: 8
Any progress with this?

We would also like to use the same endpoint for consistency with previous solution. 
ComponentSpace
ComponentSpace
ComponentSpace Development
ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)ComponentSpace Development (4.4K reputation)

Group: Administrators
Posts: 3.2K, Visits: 11K
Our recommendation is to use separate endpoints.
However, support for this was added in v2.0.6.
The IProvider interface now includes:

Task<SamlMessageType> PeekMessageTypeAsync();



The SamlMessageType is:

public enum SamlMessageType
{
  /// <summary>
  /// Unknown.
  /// </summary>
  Unknown,

  /// <summary>
  /// Authn Request.
  /// </summary>
  AuthnRequest,

  /// <summary>
  /// SAML Response.
  /// </summary>
  SamlResponse,

  /// <summary>
  /// Logout Request.
  /// </summary>
  LogoutRequest,

  /// <summary>
  /// Logout Resoonse.
  /// </summary>
  LogoutResponse
}



The following example code is how an identity provider would handle SSO and SLO messages sent to the same endpoint.

switch (await _samlIdentityProvider.PeekMessageTypeAsync())
{
  case SamlMessageType.AuthnRequest:
   var ssoResult = await _samlIdentityProvider.ReceiveSsoAsync();
   break;

  case SamlMessageType.LogoutRequest:
  case SamlMessageType.LogoutResponse:
   var sloResult = await _samlIdentityProvider.ReceiveSloAsync();
   break;
}



The following example code is how a service provider would handle SSO and SLO messages sent to the same endpoint.

switch (await _samlServiceProvider.PeekMessageTypeAsync())
{
  case SamlMessageType.SamlResponse:
   var ssoResult = await _samlServiceProvider.ReceiveSsoAsync();
   break;

  case SamlMessageType.LogoutRequest:
  case SamlMessageType.LogoutResponse:
   var sloResult = await _samlServiceProvider.ReceiveSloAsync();
   break;
}




Regards
ComponentSpace Development
GO


Similar Topics


Execution: 0.000. 2 queries. Compression Enabled.
Login
Existing Account
Email Address:


Password:


Select a Forum....












Forums, Documentation & Knowledge Base - ComponentSpace


Search