Shibboleth Identity Provider

Shibboleth is an open source and standards-based software package for a web to implement sign sign-on across or within the organizational boundaries. For further knowledge of Shibboleth Identity provider, we first need to know what is Identity Provider (IDP)?

What is Identity Provider?

Identity provider or Identity Assertion provider is an online service to maintain, manage, and create identity information for principles while providing authentication service. It authenticates users to provide security on the internet by using tokens. Once it completes the authentication, it sends back the user token to the requesting service provider. A Service Provider provides web services that need the information of the authenticated users from the IdP.

What is SAML?

Shibboleth doesn’t work single-handedly; it implements SAML (Security Assertion Markup Language) to provide single sign-on and attribute exchange framework. SAML (Security Assertion Markup Language) is an open standard to use one set of credentials to sign into multiple and different websites. You can learn more about it here: What is SAML and how does it work? You can also refer SAML library to work with .NET.

Shibboleth Identity Provider

Shibboleth Identity Provider is an Identity provider web package to implement single sign-on facility on the web application and user authentication to authenticate the user information and provide security to the user by providing token-based authentication. It also provides a huge set of user-related data to services to the personalized user experience.

Normal Process of Shibboleth Identity Provider

  • Accept user wanted SAML authentication request from the service provider.
  • Authenticate user across organization’s existing authentication stores.
  • Compile user data from an organization’s existing data stores.
  • Implement policies to control which data is a move to which service provider.
  • Collected information securely transfer to Service Provider.

Key Features of Shibboleth Identity Provider

  • It provides support for reading user data from LDAP directories and relational database.
  • It performs simple and complex transformations on the obtained data.
  • It offers high and reliable support for JAAS, LDAP, Kerberos, Duo Security based authentication support.
  • Works smoothly with SAML 1.1 and SAML 2.0.
  • Provides high availability of client-side state management.
  • Gives additional options to support database and Memcache state.
  • CAS 2 SSO protocol support.
  • Very high in performance and manageability – a single instance can easily handle millions of authentications per day and easily communicate with thousands of Service Providers.
  • It has carefully managed API to allow the software to extend custom scenarios.

Implementation of Shibboleth using Ultimate SAML

First download the library from here: SAML SSO Library. Once completed, install it on your machine and navigate to the CS or VB example to play with it. The full example is located in <Installed_Folder>\Samples\Saml\Mvc\CS\Saml2-AdvancedApi\Saml2ShibbolethMvc. For VB example, replace the CS dir in that path with VB.

Below is the example illustrating how to implement Shibboleth Idp using Ultimate SAML.

In this example, you will find two projects. Saml2ShibbolethMvc.Idp acts as the Identity provider and Saml2ShibbolethMvc.SP acts as the Service Provider. We will explain the main concepts of SAML and Shibboleth Idp with code, not the entire code including template files when you create the project using Microsoft Template as it is not within the scope of this article. First, we will explain Saml2ShibbolethMvc.Idp and then Saml2Shibbolethmvc.SP.

Web.config

In web config, configuration key to run Idp and SP locally. For locally add these settings as configuration app settings key.

<add key="SingleSignOnServiceBinding" value="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"/>
    
<!-- Localhost test 
        Use these settings when running locally
        Identity Provider site runs at 'localhost:1423'
        Service Provider site runs at 'localhost:1424'            
-->
<add key="SingleSignOnServiceUrlHttpPost" value="http://localhost:1423/SingleSignOnService?binding=post" />
<add key="SingleSignOnServiceUrlHttpRedirect" value="http://localhost:1423/SingleSignOnService?binding=redirect" />
<add key="SingleSignOnServiceUrlHttpArtifact" value="http://localhost:1423/SingleSignOnService?binding=artifact" />
<add key="ArtifactIdProviderUrl" value="http://localhost:1423/SamlArtifactResolve" />
<add key="LogoutIdProviderUrl" value="http://localhost:1423/SingleLogoutService" />

For the production environment, you can use the settings below.

<!-- Production test 
        Use these settings when testing the apps for the production environment
        Identity Provider site runs at 'test-idp.com'
        Service Provider site runs at 'test-sp.com'
-->    
<add key="SingleSignOnServiceUrlHttpPost" value="http://test-idp.com/SingleSignOnService?binding=post" />
<add key="SingleSignOnServiceUrlHttpRedirect" value="http://test-idp.com/SingleSignOnService?binding=redirect" />
<add key="SingleSignOnServiceUrlHttpArtifact" value="http://test-idp.com/SingleSignOnService?binding=artifact" />
<add key="ArtifactIdProviderUrl" value="http://test-idp.com/SamlArtifactResolve" />
<add key="LogoutIdProviderUrl" value="http://test-idp.com/SingleLogoutService" />

SingleSignOnServiceController

Single sign-on (SSO) provides the facility to allow a user to log in to multiple applications with one set of credentials. Here is the implementation of SSO.

// The session key for saving the SSO state during a local login.
private const string SsoSessionKey = "sso";

// GET: /SingleSignOnService/    
public ActionResult Index()
{
    // Load the Single Sign-On state from the Session state.
    // If the saved authentication state is a null reference, receive the authentication request from the query string and form data.
    SsoAuthnState ssoState = (SsoAuthnState)Session[SsoSessionKey];

    if (ssoState == null || !HttpContext.User.Identity.IsAuthenticated)
    {
        // Receive the authentication request.
        AuthnRequest authnRequest;
        string relayState;

        Util.ProcessAuthnRequest(HttpContext, out authnRequest, out relayState);

        if (authnRequest == null)
        {
            // No authentication request found.
            goto ReturnView;
        }

        // Process the authentication request.
        bool forceAuthn = authnRequest.ForceAuthn;
        bool allowCreate = false;

        if (authnRequest.NameIdPolicy != null)
        {
            allowCreate = authnRequest.NameIdPolicy.AllowCreate;
        }

        ssoState = new SsoAuthnState();
        ssoState.AuthnRequest = authnRequest;
        ssoState.State = relayState;

        // Determine whether or not a local login is required.
        bool requireLocalLogin = false;

        if (forceAuthn)
        {
            requireLocalLogin = true;
        }
        else
        {
            if (!User.Identity.IsAuthenticated & allowCreate)
            {
                requireLocalLogin = true;
            }
        }

        // If a local login is required then save the authentication request 
        // and initiate a local login.
        if (requireLocalLogin)
        {
            // Save the SSO state.
            Session[SsoSessionKey] = ssoState;

            // Initiate a local login.
            System.Web.Security.FormsAuthentication.RedirectToLoginPage();
            goto ReturnView;
        }
    }

    // Create a SAML response with the user's local identity if any.
    ComponentPro.Saml2.Response samlResponse = Util.BuildResponse(HttpContext, ssoState.AuthnRequest);

    // Send the SAML response to the service provider.
    Util.SendResponse(HttpContext, samlResponse, ssoState.State);

ReturnView:
    return null;
}

SingleLogoutServiceController

Now we implement the Single Log Out to log off a user from all the applications.

// GET: /SingleLogoutService/
public ActionResult Index()
{
    // Receive logout request or response
    X509Certificate2 x509Certificate = (X509Certificate2)HttpContext.Application[Global.SPCertKey];

    LogoutRequest logoutRequest;
    LogoutResponse logoutResponse;
    SamlMessageUtil.CreateLogoutMessage(Request, out logoutResponse, out logoutRequest, x509Certificate.PublicKey.Key);

    if (logoutRequest != null)
        HandleLogoutRequest(logoutRequest, x509Certificate);
    else
        HandleLogoutResponse(logoutResponse);

    return null;
}

void HandleLogoutRequest(LogoutRequest message, X509Certificate2 x509Certificate)
{
    // This is the logged in ID.
    string nameId = message.NameId.NameIdentifier;

    // Do something with the ID, like writing a record about the activity of this user.
    // ...

    // Logout locally.
    FormsAuthentication.SignOut();
    Session.Abandon();

    #region Create and Send LogoutResponse
    // We need to send back a LogoutResponse to the IdP
    LogoutResponse logoutResponse = new LogoutResponse();
    logoutResponse.Status = new Status(SamlPrimaryStatusCode.Success, null);
    logoutResponse.Issuer = new Issuer(Util.GetAbsoluteUrl(HttpContext, "~/"));

    // Send the logout response.
    logoutResponse.Redirect(Response, WebConfigurationManager.AppSettings["LogoutServiceProviderUrl"], null, x509Certificate.PrivateKey);
    #endregion
}

void HandleLogoutResponse(LogoutResponse message)
{
    SamlTrace.Log(LogLevel.Info, "Received a Logout Response with status code: " + message.Status.StatusCode.ToString());

    // Redirect to the default page.
    Response.Redirect("~/", false);
}

SamlArtifactResolveController

SAML Artifact is used to secure the sensitive data such as credential information, or messages, that is not passed through the browser's query string (user can see it in the address bar).

// GET: /SamlArtifactResolve/

public ActionResult Index()
{
    try
    {
        // Create an artifact resolve from the request with XML data extracted from the request stream.
        ArtifactResolve artifactResolve = ArtifactResolve.Create(Request);

        // Create the artifact type 0004.
        Saml2ArtifactType0004 httpArtifact = new Saml2ArtifactType0004(artifactResolve.Artifact.ArtifactValue);

        // Remove the artifact state from the cache.
        XmlElement samlResponseXml = (XmlElement)SamlSettings.CacheProvider.Remove(httpArtifact.ToString());

        if (samlResponseXml == null) 
            goto ReturnView;

        // Create an artifact response containing the cached SAML message.
        ArtifactResponse artifactResponse = new ArtifactResponse();
        artifactResponse.Issuer = new Issuer(Util.GetAbsoluteUrl(HttpContext, "~/"));
        artifactResponse.Message = samlResponseXml;

        // Send the artifact response.
        artifactResponse.Send(Response);

        return null;
    }
    catch (Exception exception)
    {
        HttpContext.Trace.Write("ServiceProvider", "An Error occurred", exception);
    }

ReturnView:
    return View();
}

Util.cs

In this class, we implement some utility methods to bind Idp to SP.

public class SsoAuthnState
{
    private AuthnRequest authnRequest;
    private string state;

    public AuthnRequest AuthnRequest
    {
        get
        {
            return authnRequest;
        }
        set
        {
            authnRequest = value;
        }
    }

    public string State
    {
        get
        {
            return state;
        }
        set
        {
            state = value;
        }
    }
}

public class Util
{
    public const string RedirectBinding = "redirect";
    public const string PostBinding = "post";
    public const string ArtifactBinding = "artifact";

    /// <summary>
    /// The SP to IdP binding type query string variable.
    /// </summary>
    private const string SP2IdPBindingTypeVar = "binding";

    /// <summary>
    /// Processes the authentication request.
    /// </summary>
    /// <param name="authnRequest">The AuthnRequest object.</param>
    /// <param name="relayState">The relayState string.</param>
    public static void ProcessAuthnRequest(HttpContextBase context, out AuthnRequest authnRequest, out string relayState)
    {
        // Use a single endpoint and use a query string parameter to determine the Service Provider to Identity Provider binding type.
        string bindingType = context.Request.QueryString[SP2IdPBindingTypeVar];

        // Get the previously loaded certificate.
        X509Certificate2 cert = (X509Certificate2)context.Application[Global.SPCertKey];

        switch (bindingType)
        {
            case RedirectBinding:
                authnRequest = AuthnRequest.CreateFromHttpRedirect(context.Request.RawUrl, cert.PublicKey.Key);
                relayState = authnRequest.RelayState;
                break;

            case PostBinding:
                authnRequest = AuthnRequest.CreateFromHttpPost(context.Request);
                relayState = authnRequest.RelayState;
                break;

            case ArtifactBinding:
                Saml2ArtifactType0004 httpArtifact = Saml2ArtifactType0004.CreateFromHttpArtifactHttpForm(context.Request);

                // Create an artifact resolve request.
                ArtifactResolve artifactResolve = new ArtifactResolve();
                artifactResolve.Issuer = new Issuer(new Uri(context.Request.Url, Util.GetAbsoluteUrl(context, "~/")).ToString());
                artifactResolve.Artifact = new Artifact(httpArtifact.ToString());

                // Send the SAML Artifact Resolve Request and parse the received response.
                ArtifactResponse artifactResponse = ArtifactResponse.SendSamlMessageReceiveAftifactResponse(Global.ArtifactResolutionUrl, artifactResolve);

                // Extract the authentication request from the received artifact response.
                authnRequest = new AuthnRequest(artifactResponse.Message);
                relayState = httpArtifact.RelayState;
                break;

            default:
                throw new ApplicationException("Invalid binding type");
        }

        if (authnRequest.IsSigned())
        {
            if (!authnRequest.Validate(cert))
            {
                throw new ApplicationException("The authentication request signature failed to verify.");
            }
        }
    }

    /// <summary>
    /// Builds the SAML response.
    /// </summary>
    /// <param name="authnRequest">The AuthnRequest object.</param>
    /// <returns>A SAML Response object.</returns>
    public static ComponentPro.Saml2.Response BuildResponse(HttpContextBase context, AuthnRequest authnRequest)
    {
        ComponentPro.Saml2.Response samlResponse = new ComponentPro.Saml2.Response();
        samlResponse.Destination = Global.AssertionServiceUrl;
        Issuer issuer = new Issuer(GetAbsoluteUrl(context, "~/"));
        samlResponse.Issuer = issuer;

        if (context.User.Identity.IsAuthenticated)
        {
            samlResponse.Status = new Status(SamlPrimaryStatusCode.Success, null);

            Assertion samlAssertion = new Assertion();
            samlAssertion.Issuer = issuer;

            Subject subject = new Subject(new NameId(context.User.Identity.Name));
            SubjectConfirmation subjectConfirmation = new SubjectConfirmation(SamlSubjectConfirmationMethod.Bearer);
            SubjectConfirmationData subjectConfirmationData = new SubjectConfirmationData();
            subjectConfirmationData.InResponseTo = authnRequest.Id;
            subjectConfirmationData.Recipient = Global.AssertionServiceUrl;
            subjectConfirmation.SubjectConfirmationData = subjectConfirmationData;
            subject.SubjectConfirmations.Add(subjectConfirmation);
            samlAssertion.Subject = subject;

            AuthnStatement authnStatement = new AuthnStatement();
            authnStatement.AuthnContext = new AuthnContext();
            authnStatement.AuthnContext.AuthnContextClassRef = new AuthnContextClassRef(SamlAuthenticationContext.Password);
            samlAssertion.Statements.Add(authnStatement);

            samlResponse.Assertions.Add(samlAssertion);
        }
        else
        {
            samlResponse.Status = new Status(SamlPrimaryStatusCode.Responder, SamlSecondaryStatusCode.AuthnFailed, "The user is not authenticated at the identity provider");
        }

        return samlResponse;
    }

    /// <summary>
    /// Sends the SAML response to the Service Provider.
    /// </summary>
    /// <param name="samlResponse">The SAML response object.</param>
    /// <param name="relayState">The relay state.</param>
    public static void SendResponse(HttpContextBase context, ComponentPro.Saml2.Response samlResponse, string relayState)
    {
        // Sign the SAML response.
        X509Certificate2 x509Certificate = (X509Certificate2)context.Application[Global.IdPCertKey];
        samlResponse.Sign(x509Certificate);

        switch (Global.AssertionServiceSamlBinding)
        {
            case SamlBinding.HttpPost:
                // Send the SAML Response object.
                samlResponse.SendHttpPost(context.Response.OutputStream, Global.AssertionServiceUrl, relayState);
                break;

            case SamlBinding.HttpArtifact:
                // Create the artifact.
                string identificationUrl = GetAbsoluteUrl(context, "~/");
                Saml2ArtifactType0004 httpArtifact = new Saml2ArtifactType0004(SamlArtifact.GetSourceId(identificationUrl), SamlArtifact.GetHandle());

                // Convert the authentication request to XML and save to the Application Cache.
                SamlSettings.CacheProvider.Insert(httpArtifact.ToString(), samlResponse.GetXml(), new TimeSpan(1, 0, 0));

                // Send the artifact with POST form.
                httpArtifact.SendHttpPost(context.Response.OutputStream, Global.AssertionServiceUrl, relayState);
                break;

            default:
                throw new ApplicationException("Invalid assertion consumer service binding.");
        }
    }

    public static string GetAbsoluteUrl(HttpContextBase context, string relativeUrl)
    {
        return new Uri(context.Request.Url, System.Web.Mvc.UrlHelper.GenerateContentUrl(relativeUrl, context)).ToString();
    }
}

AccountController

It's to implement login and logoff requests. Here is our code snippet:

// GET: /Account/Login
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
    // If the user is already logged in, redirect to the homepage
    if (HttpContext.User.Identity.IsAuthenticated)
        return RedirectToAction("Index", "Home");

    ViewBag.ReturnUrl = returnUrl;
    return View();
}

[HttpPost]
[AllowAnonymous]
public ActionResult Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        // Validate user
        if (model.UserName == "iuser" && model.Password == "password")
        {
            FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);

            if (!String.IsNullOrEmpty(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }
        else
            ModelState.AddModelError("", "The user name or password provided is incorrect.");
    }

    // If we got this far, something failed, redisplay form
    return View(model);
}

// **************************************
// URL: /Account/LogOff
// **************************************

public ActionResult LogOff()
{
    // Create a logout request.
    LogoutRequest logoutRequest = new LogoutRequest();
    logoutRequest.Issuer = new Issuer(Util.GetAbsoluteUrl(HttpContext, "~/"));
    logoutRequest.NameId = new NameId(HttpContext.User.Identity.Name);

    // Send the logout request to the SP over HTTP redirect.
    string logoutUrl = WebConfigurationManager.AppSettings["LogoutServiceProviderUrl"];
    X509Certificate2 x509Certificate = (X509Certificate2)HttpContext.Application[Global.IdPCertKey];

    logoutRequest.Redirect(Response, logoutUrl, logoutUrl, x509Certificate.PrivateKey);

    // Log out locally.
    FormsAuthentication.SignOut();
    Session.Abandon();

    return null;
}

Global.asax.cs

In this file, we load the Idp and SP certificates and verifies the remote Secure Sockets Layer (SSL) certificate used for authentication.

private const string IdPKeyFile = "IdpKey.pfx";
private const string IdPKeyPassword = "password";

private const string SPCertFile = "SPCertificate.cer";

public const string IdPCertKey = "IdPCertKey";
public const string SPCertKey = "SPCertKey";

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default", // Route name
        "{controller}/{action}/{id}", // URL with parameters
        new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
    );

}

protected void Application_Start()
{
    ComponentPro.Licensing.Saml.LicenseManager.SetLicenseKey(ComponentPro.LicenseKey.Key);
    AreaRegistration.RegisterAllAreas();

    RegisterRoutes(RouteTable.Routes);

    // Set server certificate validation callback.
    ServicePointManager.ServerCertificateValidationCallback = ValidateRemoteServerCertificate;

    // Load the IdP key file.
    LoadCertificate(IdPCertKey, Path.Combine(HttpRuntime.AppDomainAppPath, IdPKeyFile), IdPKeyPassword);

    // Load the SP cert file.
    LoadCertificate(SPCertKey, Path.Combine(HttpRuntime.AppDomainAppPath, SPCertFile), null);
}

// SAML
public const string CertKeyName = "Cert";

/// <summary>
/// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication.
/// </summary>
/// <param name="sender">An object that contains state information for this validation.</param>
/// <param name="certificate">The certificate used to authenticate the remote party.</param>
/// <param name="chain">The chain of certificate authorities associated with the remote certificate.</param>
/// <param name="sslPolicyErrors">One or more errors associated with the remote certificate.</param>
/// <returns>A System.Boolean value that determines whether the specified certificate is accepted for authentication.</returns>
private static bool ValidateRemoteServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    // NOTE: This is a test application with self-signed certificates, so all certificates are trusted.
    return true;
}

/// <summary>
/// Loads the certificate file.
/// </summary>
/// <param name="cacheKey">The cache key.</param>
/// <param name="fileName">The certificate file name.</param>
/// <param name="password">The password for this certificate file.</param>
private void LoadCertificate(string cacheKey, string fileName, string password)
{
    X509Certificate2 cert = new X509Certificate2(fileName, password, X509KeyStorageFlags.MachineKeySet);

    Application[cacheKey] = cert;
}

#region Config

private const string AssertionServiceSamlBindingKey = "AssertionServiceSamlBinding";
private const string AssertionServiceUrlHttpPostKey = "AssertionServiceUrlHttpPost";
private const string AssertionServiceUrlHttpArtifactKey = "AssertionServiceUrlHttpArtifact";
private const string ArtifactResolutionUrlKey = "ArtifactResolutionUrl";

public static SamlBinding AssertionServiceSamlBinding
{
    get
    {
        return SamlBindingUri.UriToBinding(WebConfigurationManager.AppSettings[AssertionServiceSamlBindingKey]);
    }
}

public static string AssertionServiceUrl
{
    get
    {
        switch (AssertionServiceSamlBinding)
        {
            case SamlBinding.HttpPost:
                return AssertionServiceUrlHttpPost;

            case SamlBinding.HttpArtifact:
                return AssertionServiceUrlHttpArtifact;

            default:
                throw new ArgumentException("Invalid assertion consumer service binding");
        }
    }
}

public static string AssertionServiceUrlHttpPost
{
    get
    {
        return WebConfigurationManager.AppSettings[AssertionServiceUrlHttpPostKey];
    }
}

public static string AssertionServiceUrlHttpArtifact
{
    get
    {
        return WebConfigurationManager.AppSettings[AssertionServiceUrlHttpArtifactKey];
    }
}

public static string ArtifactResolutionUrl
{
    get
    {
        return WebConfigurationManager.AppSettings[ArtifactResolutionUrlKey];
    }
}

#endregion

Now we will discuss the SP project files. Most files are same as Idp project. The difference in the file AssertionServiceController and SingleLogoutServiceController.

AssertionServiceController

In this we take SAML response and process it

public ActionResult Index()
{
    ComponentPro.Saml2.Response samlResponse = null;
    string relayState = null;

    // Get and process the SAML response.
    Util.ProcessResponse(HttpContext, out samlResponse, out relayState);

    // If the SAML response indicates success.
    if (samlResponse.IsSuccess())
    {
        Util.SamlSuccessRedirect(HttpContext, samlResponse, relayState);
    }
    else
    {
        Util.SamlErrorRedirect(HttpContext, samlResponse);
    }

    return View();
}

SingleLogoutServiceController

In this file, we load the previous certificates that we use in Idp and handle log out in SP side.

// GET: /SingleLogoutService/
public ActionResult Index()
{
    // Get the previously loaded certificate.
    X509Certificate2 x509Certificate = (X509Certificate2)HttpContext.Application[Global.IdPCertKey];

    LogoutResponse logoutResponse;
    LogoutRequest logoutRequest;

    // Extract the LogoutResponse or LogoutRequest from the request
    SamlMessageUtil.CreateLogoutMessage(Request, out logoutResponse, out logoutRequest, x509Certificate.PublicKey.Key);

    // Handle the LogoutRequest and LogoutResponse accordingly.
    if (logoutRequest != null)
        HandleLogoutRequest(logoutRequest, x509Certificate);
    else
        HandleLogoutResponse(logoutResponse);

    return null;
}

void HandleLogoutRequest(LogoutRequest message, X509Certificate2 x509Certificate)
{
    // This is the logged in ID.
    string nameId = message.NameId.NameIdentifier;

    // Do something with the ID, like writing a record about the activity of this user.
    // ...

    // Log out locally.
    System.Web.Security.FormsAuthentication.SignOut();
    Session.Abandon();

    #region Create and Send LogoutResponse
    // We need to send back a LogoutResponse to the IdP
    LogoutResponse logoutResponse = new LogoutResponse();
    logoutResponse.Status = new Status(SamlPrimaryStatusCode.Success, null);
    logoutResponse.Issuer = new Issuer(Util.GetAbsoluteUrl(HttpContext, "~/"));

    // Send the logout response.
    logoutResponse.Redirect(Response, WebConfigurationManager.AppSettings["LogoutIdProviderUrl"], null, x509Certificate.PrivateKey);
    #endregion
}

void HandleLogoutResponse(LogoutResponse message)
{
    SamlTrace.Log(LogLevel.Info, "Received a Logout Response with status code: " + message.Status.StatusCode.ToString());

    // Redirect to the default page.
    Response.Redirect("~/", false);
}

Now start the solution you will see this screen where you need to log in to use the mention credentials, and you will be logged in both the projects IdP and SP.

Shibboleth SP login login at SP

Now use credentials to log in at SP you will be redirected to Home page and refresh the Idp log in you will see you are automatically redirected to the Home page of IdP.

SP logged in IdP logged in

Pros

  • Shibboleth is an open source, and there is no cost for a license.
  • You can run your IIS, and you don’t need self-service configuration changes.
  • It saves your time by providing software-based SAML service provider.
  • It is highly preferable to use a SAML service provider for identity federations.
  • Shibboleth IDP has commercial support also.

Cons

  • It uses configuration files that we need to restart our server when updating the Shibboleth installation settings.
  • It bases on Java, so it takes extra memory on Windows.
  • It is also difficult and tricky to implement.
  • To implement with .NET, you need some time and have good knowledge to work with it.

45-Day Money Back Guarantee

We will refund your full money in 45 days
if you are not satisfied with our products

Buy Now

Dont miss out Get update on new articles and other opportunities