다음을 통해 공유


ADFS 2.0 use BOTH Forms based and Windows Authentication

Customer required forms based and windows authentication on a single farm for an internal saas application. By default, ADFS will only allow one type of authentication. This MSDN article describes how to edit the IdpInitiatedSignOn.aspx.cs file to enable sign-on parameters in the query string. In the end, you will be able to specify URLs that dictate the authentication type.

Example:
Normal IDP initiated link to visit relying party SAAS application:
https://sts.example.com/adfs/ls/idpinitiatedsignon.aspx?logintorp=http://saasvendors.example.com

URL with query string that forces the users into a forms based logon and then sends them to the SAAS application:
https://sts.example.com/adfs/ls/IdpInitiatedSignon.aspx?logintorp=http://saasvendors.example.com&RequestedAuthenticationContext=urn:oasis:names:tc:SAML:2.0:ac:classes:Password

Follow the extract from the MSDN article to enable this feature

Reference:

http://msdn.microsoft.com/en-us/library/ee895361.aspx

Example: Add Support for Sign-On Parameters in the Query String

The default behavior provided in the Page_Load event handler in IdpInitiatedSignOn.aspx.cs supports a single parameter in the query string, loginToRp. This parameter specifies the identity of the RP to sign on to. However, this default behavior does not provide for any of the other properties available through the SignOnRequestParameters class to be passed in the query string. The code in this example modifies the Page_Load event handler so that these properties can be specified by using additional query string parameters. With this code, the following additional query string parameters and syntax are supported.

Consent: A SAML consent identifier URI. If this parameter is omitted, the default is urn:oasis:names:tc:SAML:2.0:consent:unspecified.

IsPassive: true | false. If this parameter is omitted, the default is false.

ForcedAuthentication: true | false. If this parameter is omitted, the default is false.

RequestAuthenticationContext: One of the supported SAML authentication context class URIs. If this parameter is omitted, no authentication context class is specified during sign-on.

AuthenticationContextComparison: Better | Exact | Maximum | Minimum. If this parameter is omitted, the default is Exact. The value is case-sensitive.

Note 
The query parameters are only valid if the loginToRp parameter is specified (although its value can be an empty string to specify the IdP). The AuthenticationContextComparison parameter is only valid if the RequestAuthenticationContext parameter is specified, and its value is case sensitive. Only one authentication context class URI may be passed in the RequestAuthenticationContext parameter. It does not make sense to set the ForcedAuthentication and the IsPassive parameters both to true.
 

By using these parameters, sign-on query strings like the following may be specified.

To sign on to the RP with no sign-on page being presented to the user (this will fail if a session does not already exist with the user): https://adfs-server.contoso.com/adfs/ls/IdpInitiatedSignon.aspx?logintorp=urn:samples:serviceprovider:myservice&ispassive=true

To force authentication by the user even if a session already exists: https://adfs-server.contoso.com/adfs/ls/IdpInitiatedSignon.aspx?logintorp=urn:samples:serviceprovider:myservice&ForceAuthentication=true

To specify user name-password authentication: https://adfs-server.contoso.com/adfs/ls/IdpInitiatedSignon.aspx?logintorp=urn:samples:serviceprovider:myservice&RequestedAuthenticationContext=urn:oasis:names:tc:SAML:2.0:ac:classes:Password

To specify an authentication method that is stronger than username-password authentication (as defined by the IdP): https://adfs-server.contoso.com/adfs/ls/IdpInitiatedSignon.aspx?logintorp=urn:samples:serviceprovider:myservice&RequestedAuthenticationContext=urn:oasis:names:tc:SAML:2.0:ac:classes:Password&AuthenticationContextComparison=Better

To modify the default IdpInitiatedSignOn.aspx.cs code-behind to provide support for these additional query string parameters, first add a using statement for the Microsoft.IdentityServer.Protocols.Saml namespace to the top of the file.

Copy
 
using Microsoft.IdentityServer.Protocols.Saml;

Next add the following string constants to the code-behind class to define the query string parameters.

Copy
 
    const string RpIdentityQueryParameter = "loginToRp";
    const string IsPassiveQueryParameter = "IsPassive";
    const string ForceAuthenticationQueryParameter = "ForceAuthentication";
    const string AuthenticationContextComparisonQueryParameter = "AuthenticationContextComparison";
    const string RequestedAuthenticationContextQueryParameter = "RequestedAuthenticationContext";
 
    const string IdpAsRpIdentifier = "self";

Note 
RpIdentityQueryParameter and IdpAsRpIdentifier are already defined in the default IdpInitiatedSignOn.aspx.cs file.
 

Next, replace the Page_Init method with the following code. This code extracts the sign-on parameters from the query string and uses them to create a SignOnRequestParameters object that it then passes to the SignIn method.

Copy
 
    protected void Page_Init(object sender, EventArgs e)
    {
        PopulateConditionalVisibilityControls();

        RelyingPartyDropDownList.DataSource = RelyingParties;
        RelyingPartyDropDownList.DataBind();

        UpdateText();

        string rpIdentity = Context.Request.QueryString[RpIdentityQueryParameter];

       
        //
        // If the query string specified a certain relying party, sign in to that relying party.
        //
        if (!String.IsNullOrEmpty(rpIdentity))
        {
            string decodedIdentity = Server.UrlDecode(rpIdentity);
            if (decodedIdentity == IdpAsRpIdentifier)
            {
                rpIdentity = String.Empty;
            }

            SignOnRequestParameters parameters = new SignOnRequestParameters();
            string isPassive = Context.Request.QueryString[IsPassiveQueryParameter];
            if (!String.IsNullOrEmpty(isPassive))
            {
                parameters.IsPassive = Boolean.Parse(isPassive);
            }
            string forceAuthentication = Context.Request.QueryString[ForceAuthenticationQueryParameter];
            if (!String.IsNullOrEmpty(forceAuthentication))
            {
                parameters.ForceAuthentication = Boolean.Parse(forceAuthentication);
            }
            string requestedAuthentication = Context.Request.QueryString[RequestedAuthenticationContextQueryParameter];
            if (!String.IsNullOrEmpty(requestedAuthentication))
            {
                if (parameters.RequestedAuthenticationContext == null)
                {
                    parameters.RequestedAuthenticationContext = new RequestedAuthenticationContext();
                }
                parameters.RequestedAuthenticationContext.References.Add(new Uri(requestedAuthentication));
                string comparison = Context.Request.QueryString[AuthenticationContextComparisonQueryParameter];
                if (!String.IsNullOrEmpty(comparison))
                {
                    parameters.RequestedAuthenticationContext.Comparison = (AuthenticationContextComparisonType)Enum.Parse(typeof(AuthenticationContextComparisonType), comparison);
                }
            }
           
            SignIn(rpIdentity, parameters);
        }
    }