0

認証なしで完全に正常に動作する WCF データ サービスを作成しました。次に、以下のようにアプリケーションに HttpModule を追加して、認証コードを追加したいと思いました。

public class BasicIdentity : IIdentity
{
    string _name;

    public BasicIdentity(string name)
    {
        this._name = name;
    }

    string IIdentity.AuthenticationType
    {
        get { return "Custom SCHEME"; }
    }

    bool IIdentity.IsAuthenticated
    {
        get { return true; }
    }

    string IIdentity.Name
    {
        get { return _name; }
    }
}

public class BasicPrincipal : IPrincipal
{
    string[] _roles;
    IIdentity _identity;

    public BasicPrincipal(string name, params string[] roles)
    {
        this._roles = roles;
        this._identity = new CustomIdentity(name);
    }

    public IIdentity Identity
    {
        get { return _identity; }
    }

    public bool IsInRole(string role)
    {
        return _roles.Contains(role);
    }
}

public class BasicAuthenticationProvider
{
    public static bool Authenticate(HttpContext context)
    {
        //if (!HttpContext.Current.Request.IsSecureConnection)
        //    return false;

        if (!HttpContext.Current.Request.Headers.AllKeys.Contains("Authorization"))
            return false;

        string authHeader = HttpContext.Current.Request.Headers["Authorization"];

        IPrincipal principal;
        if (TryGetPrincipal(authHeader, out principal))
        {
            HttpContext.Current.User = principal;
            return true;
        }
        return false; 
    }

    private static bool TryGetPrincipal(string authHeader, out IPrincipal principal)
    {
        // 
        // WARNING: 
        // our naive – easily mislead authentication scheme 
        // blindly trusts the caller. 
        // a header that looks like this: 
        // ADMIN username 
        // will result in someone being authenticated as an 
        // administrator with an identity of ‘username’ 
        // i.e. not exactly secure!!! 
        // 
        //var protocolParts = authHeader.Split(' ');
        //if (protocolParts.Length != 2)
        //{
        //    principal = null;
        //    return false;
        //}
        //else if (protocolParts[0] == "ADMIN")
        //{
        //    principal = new CustomPrincipal(
        //       protocolParts[1],
        //       "Administrator", "User"
        //    );
        //    return true;
        //}
        //else if (protocolParts[0] == "USER")
        //{
        //    principal = new CustomPrincipal(
        //       protocolParts[1],
        //       "User"
        //    );
        //    return true;
        //}
        //else
        //{
        //    principal = null;
        //    return false;
        //}
        var creds = ParseAuthHeader(authHeader);
        if (creds != null && TryGetPrincipal(creds, out principal))
            return true;

        principal = null;
        return false; 
    }

    private static string[] ParseAuthHeader(string authHeader)
    {
        // Check this is a Basic Auth header 
        if (
            authHeader == null ||
            authHeader.Length == 0 ||
            !authHeader.StartsWith("Basic")
        ) return null;

        // Pull out the Credentials with are seperated by ':' and Base64 encoded 
        string base64Credentials = authHeader.Substring(6);
        string[] credentials = Encoding.ASCII.GetString(
              Convert.FromBase64String(base64Credentials)
        ).Split(new char[] { ':' });

        if (credentials.Length != 2 ||
            string.IsNullOrEmpty(credentials[0]) ||
            string.IsNullOrEmpty(credentials[0])
        ) return null;

        // Okay this is the credentials 
        return credentials;
    }

    private static bool TryGetPrincipal(string[] creds, out IPrincipal principal)
    {
        if (creds[0] == "Administrator" && creds[1] == "SecurePassword")
        {
            principal = new GenericPrincipal(
               new GenericIdentity("Administrator"),
               new string[] { "Administrator", "User" }
            );
            return true;
        }
        else if (creds[0] == "JoeBlogs" && creds[1] == "Password")
        {
            principal = new GenericPrincipal(
               new GenericIdentity("JoeBlogs"),
               new string[] { "User" }
            );
            return true;
        }
        else
        {
            principal = null;
            return false;
        }
    }
}

public class BasicAuthenticationModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.AuthenticateRequest
           += new EventHandler(context_AuthenticateRequest);
    }
    void context_AuthenticateRequest(object sender, EventArgs e)
    {
        HttpApplication application = (HttpApplication)sender;
        if (!BasicAuthenticationProvider.Authenticate(application.Context))
        {
            application.Context.Response.Status = "401 Unauthorized";
            application.Context.Response.StatusCode = 401;
            application.Context.Response.AddHeader("WWW-Authenticate", "Basic");
            application.CompleteRequest();
        }
    }
    public void Dispose() { }
}

ここで、BasicAuthenticationModule は web.config に次のように登録されます。

 <system.web>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      </assemblies>
    </compilation>
    <httpModules>
      <add name="BasicAuthenticationModule"
     type="ODataEmptyWebApp.BasicAuthenticationModule"/>
    </httpModules>
 </system.web>

ブラウザで WCF Data Service を実行すると、認証ウィンドウが表示されます。無効な資格情報を入力すると、正しい資格情報を要求し続けます。正しい資格情報、つまり Administrator/SecuredPassword を入力すると、ウィンドウが閉じて空のページが表示されます。ページのソース コードは次のとおりです。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv="Content-Type" 
content="text/html; charset=windows-1252"></HEAD>
<BODY></BODY></HTML>

コードをデバッグすると、HttpModule を追加する前に呼び出されていた WCF Data Service の Initialize メソッドが呼び出されないことがわかりました。

コントロールが Initialize メソッドに渡されない理由がわかりません。実行するには明示的に何かを追加する必要がありますか??

4

0 に答える 0