Created by

ITfoxtec
Anders Revsgaard
support@itfoxtec.com

Download

Version: 1.2.4 - History
Supporting .NET 4.5

NuGet ITfoxtec SAML 2.0
NuGet ITfoxtec SAML 2.0 MVC
License
GetHub code and example

ITfoxtec SAML 2.0

Maintenance of this component is discontinued. Please use the ITfoxtec Identity SAML 2.0 component instead.

The open source ITfoxtec SAML 2.0 package adds SAML-P support on top of the SAML 2.0 token functionality implemented in the .NET framework. .NET implements a reasonably part of the SAML 2.0 token standard but it is completely lacking support for SAML-P.

The ITfoxtec SAML 2.0 package implements the most important parts of the SAML-P standard and some optional features. Message signing and validation as well as decryption is supported. The package supports SAML 2.0 login, logout, single logout and metadata. Both SP Initiated and IdP Initiated sign on is supported.
The SAML 2.0 package is tested for compliance with Active Directory Federation Services (AD FS).
The Danish OIOSAML 2.0 profile is supported and tested for compliance with NemLog-in.

Supported bindings:

  • Redirect Binding
  • Post Binding

The bindings can be used as needed for:

  • Authn Request
  • Authn Response (SAML 2.0 Response)
  • Logout Request
  • Logout Response

ASP.NET MVC is supported by the ITfoxtec SAML 2.0 MVC package which helps to integrate the ITfoxtec SAML 2.0 package into a MVC application. The code examples underneath shows the ASP.NET MVC integration.

Web Farms is supported by configuring Windows Identity Foundation (WIF), see WIF and Web Farms.

Code

The SAML 2.0 package is integrated into a ASP.NET MVC application by adding an Auth Controller and implementing the following four methods. The binding shown can be changed as needed depending on the requirements.

It is furthermore possible to set some optional parameters on the Saml2AuthnRequest and Saml2LogoutRequest. On the Saml2AuthnRequest e.g. ForceAuthn is supported, which will force the user to enter login credentials even though an SSO context already exists on the Security Token Service (STS) in this case a AD FS.


Login method in the Auth Controller

The example shows how to use the RequestedAuthnContext, which can be omitted.
public ActionResult Login(string returnUrl)
{
    var binding = new Saml2RedirectBinding();
    binding.SetRelayStateQuery(new Dictionary<string, string> { { "ReturnUrl", returnUrl } });

    return binding.Bind(new Saml2AuthnRequest
        {
            RequestedAuthnContext = new RequestedAuthnContext
            {
                Comparison = AuthnContextComparisonTypes.Exact,
                AuthnContextClassRef = new string[] { AuthnContextClassTypes.PasswordProtectedTransport.OriginalString }, 
            },
            Issuer = new EndpointReference("http://udv.itfoxtec.com/webapptest"),
            Destination = new EndpointAddress("https://udv.itfoxtec.com/adfs/ls/"),
            AssertionConsumerServiceUrl = new EndpointAddress("https://udv.itfoxtec.com/webapptest/Auth/AssertionConsumerService")
        }).ToActionResult();
}

AssertionConsumerService method in the Auth Controller

After successfully or failing login the ACS method receiver the response.
public ActionResult AssertionConsumerService()
{
    var binding = new Saml2PostBinding();
    var saml2AuthnResponse = new Saml2AuthnResponse();

    binding.Unbind(Request, saml2AuthnResponse, CertificateUtil.Load("~/App_Data/signing-adfs.test_Certificate.crt"));
    saml2AuthnResponse.CreateSession();

    var returnUrl = binding.GetRelayStateQuery()["ReturnUrl"];
    return new RedirectResult(string.IsNullOrWhiteSpace(returnUrl) ? Url.Content("~/") : returnUrl);
}

Logout method in the Auth Controller

public ActionResult Logout()
{
    if (!User.Identity.IsAuthenticated)
    {
        return Redirect(Url.Content("~/"));
    }

    var binding = new Saml2PostBinding();
    return binding.Bind(new Saml2LogoutRequest
        {
            Issuer = new EndpointReference("http://udv.itfoxtec.com/webapptest"),
            Destination = new EndpointAddress("https://udv.itfoxtec.com/adfs/ls/")
        },
        CertificateUtil.Load("~/App_Data/webapptest_certificate.pfx")).ToActionResult();
}

LoggedOut method in the Auth Controller

After successfully or failing logout the logged out method receive the response.
public ActionResult LoggedOut()
{
    var binding = new Saml2RedirectBinding();
    binding.Unbind(Request, new Saml2LogoutResponse(), CertificateUtil.Load("~/App_Data/signing-adfs.test_Certificate.crt")).DeleteSession();

    return Redirect(Url.Content("~/"));
}

SingleLogout method in the Auth Controller

Receives a Single Logout request and send a response.
public ActionResult SingleLogout()
{
    Saml2StatusCodes status;
    var requestBinding = new Saml2RedirectBinding();
    var logoutRequest = new Saml2LogoutRequest();
    try
    {
        requestBinding.Unbind(Request, logoutRequest, CertificateUtil.Load("~/App_Data/signing-adfs.test_Certificate.crt"));
        status = Saml2StatusCodes.Success;
    }
    catch (Exception exc)
    {
        // log exception
        Debug.WriteLine("SingleLogout error: " + exc.ToString());
        status = Saml2StatusCodes.RequestDenied;
    }

    var responsebinding = new Saml2RedirectBinding();
    responsebinding.RelayState = requestBinding.RelayState;
    var saml2LogoutResponse = new Saml2LogoutResponse
    {
        InResponseTo = logoutRequest.Id,
        Status = status,
        Issuer = new EndpointReference("http://udv.itfoxtec.com/webapptest"),
        Destination = new EndpointAddress("https://udv.itfoxtec.com/adfs/ls/")
    };
    saml2LogoutResponse.DeleteSession();
    return responsebinding.Bind(saml2LogoutResponse, CertificateUtil.Load("~/App_Data/webapptest_certificate.pfx")).ToActionResult();        
}