简体   繁体   中英

How “WebRequest” object determine the “IAuthenticationModule” implementation to use?

I would like to use System.Net's AuthenticationManager class to define the basic or bearer authorization header of a WebRequest .

AuthenticationManager provides a Register method to add a new module (implementation of IAuthenticationModule ). This suggests that it is possible to register multiple modules and that there is a way to select one of these modules.

And I suppose that module selection must be done by giving the value that is defined in the "AuthenticationType" property of the module. I define it in a CredentialCache that I pass to my "WebRequest".

I tried to create and save 2 modules:

  • A module to redefine the basic authorization (to disable the pre-authentication) (I use the example of the Microsoft documentation: here )
  • A module for authorization bearer.

Then I save my 2 modules in AuthenticationManager with the following code:

// I remove the previous basic module 
AuthenticationManager.Unregister("Basic");

// And i register my 2 modules
AuthenticationManager.Register(customBasicModule);
AuthenticationManager.Register(customBearerModule);

But it seems that this is always the first record module that is called.

My test code:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://example.com");

var cache = new CredentialCache();
cache.Add(new Uri("http://example.com"), "Basic", new NetworkCredential("user", "password"));

request.Method = "GET";    
request.Credentials = cache;

HttpWebResponse response = (HttpWebResponse)request.GetResponse();

I expect the "customBasicModule" to be called because I indicated "Basic" in the property "AuthenticationType" of this module and also in the "CredentialCache". But if I register the "customBearerModule" first, it will be called.

Modules :

public class BasicAuthenticationModule : IAuthenticationModule
{
    private const string BASIC_SCHEME = "Basic";

    public bool CanPreAuthenticate => false;

    public string AuthenticationType => BASIC_SCHEME;

    public Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials)
    {
        // Some code to get Basic from ICredentials
    }

    public Authorization PreAuthenticate(WebRequest request, ICredentials credentials)
    {
        return null;
    }
}

public class BearerAuthenticationModule : IAuthenticationModule
{
    private const string BEARER_SCHEME = "Bearer";

    public bool CanPreAuthenticate => false;

    public string AuthenticationType => BEARER_SCHEME;

    public Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials)
    {
        // Some code to get Bearer from ICredentials
    }

    public Authorization PreAuthenticate(WebRequest request, ICredentials credentials)
    {
        return null;
    }
}

The AuthenticationManager will always call all IAuthenticationModule in the order they have been register until one return a non null Authorization instance.

The idea is that each IAuthenticationModule implementation is expected to validate the challenge parameter against what they are able to do and return null if they do not match.

So your implementations should looks to

public class BasicAuthenticationModule : IAuthenticationModule
{
    private const string BASIC_SCHEME = "Basic";

    public bool CanPreAuthenticate => false;

    public string AuthenticationType => BASIC_SCHEME;

    public Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials)
    {
        if (!challenge.StartWith(BASIC_SCHEME)) return null;
        // Some code to get Basic from ICredentials
    }

    public Authorization PreAuthenticate(WebRequest request, ICredentials credentials)
    {
        return null;
    }
}

public class BearerAuthenticationModule : IAuthenticationModule
{
    private const string BEARER_SCHEME = "Bearer";

    public bool CanPreAuthenticate => false;

    public string AuthenticationType => BEARER_SCHEME;

    public Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials)
    {
        if (!challenge.StartWith(BEARER_SCHEME)) return null;
        // Some code to get Bearer from ICredentials
    }

    public Authorization PreAuthenticate(WebRequest request, ICredentials credentials)
    {
        return null;
    }
}

Also pay attention that the challenge is the content of the WWW-Authenticate header send by the server after a first unauthorized response (401) which is not related to the "basic" that you write in the CredentialCache

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM