web-dev-qa-db-ja.com

例によるDropWizard認証

DropWizard での認証と承認の仕組みを理解しようとしています。私はGitHubの auth guidedropwizard-security プロジェクトを読みましたが、まだいくつかの重要な概念が欠けているように感じます。

public class SimpleCredential {
    private String password;

    public SimpleCredential(String password) {
        super();

        this.password = password;
    }
}

public class SimplePrincipal {
    pivate String username;

    public SimplePrincipal(String username) {
        super();

        this.username = username;
    }
}

public class SimpleAuthenticator implements Authenticator<SimpleCredential, SimplePrincipal> {
    @Override
    public Optional<SimplePrincipal> authenticate(SimpleCredential credential) throws AuthenticationException {
        if(!"12345".equals(credential.getPassword())) {
            throw new AuthenticationException("Sign in failed.");
        }

        Optional.fromNullable(new SimplePrincipal("simple_user"));
    }
}

そして、私のApplicationサブクラスで:

@Override
public void run(BackendConfiguration configuration, Environment environment) throws Exception {
    environment.jersey().register(new BasicAuthProvider<SimplePrincipal>(new SimpleAuthenticator(), "SUPER SECRET STUFF"));
}

そして、リソースメソッドで:

@GET
@Path("address/{address_id}")
@Override
public Address getAddress(@Auth @PathParam("address_id") Long id) {
    addressDao.getAddressById(id);
}

私はこれを基本認証用に正しく設定したと思いますが、SimpleCredentialSimplePrincipalが果たす役割を理解していません。具体的には:

  1. Jersey/JAX-RSクライアントから基本認証ユーザー名/パスワードを設定するにはどうすればよいですか?
  2. SimpleCredentialSimplePrincipalは基本認証でどのような役割を果たしますか?唯一の有効なユーザー名がsimple_userで唯一の有効なパスワードが12345であるように、基本認証を機能させるためにそれらまたは他のクラスに何かを追加する必要がありますか?
  3. SimplePrincipalを介してアクセス/認証/ロールを適用するにはどうすればよいですか?または、承認の概念がWebサービスに存在しないのですか?
21
IAmYourFaja

質問1:

基本認証 プロトコルは、クライアント要求に次の形式のヘッダーが必要であることを示します

_Authorization: Basic Base64Encoded(username:password)
_

ここで、Base64Encoded(username:password)は、_username:password_の実際のBase64エンコード文字列です。たとえば、ユーザー名とパスワードが_peeskillet:pass_の場合、ヘッダーは次のように送信されます。

_Authorization: Basic cGVlc2tpbGxldDpwYXNz
_

とはいえ、Jersey Client(1.xと仮定)には、クライアント側のフィルターであるHTTPBasicAuthFilterがあり、これがエンコード部分を処理します。したがって、クライアント側のリクエストは次のようになります

_Client client = Client.create();
WebResource resource = client.resource(BASE_URI);
client.addFilter(new HTTPBasicAuthFilter("peeskillet", "pass"));
String response = resource.get(String.class);
_

これが、認証ヘッダーを使用した単純なGETリクエストを作成するために必要なすべてのことです。

質問2:

SimpleCredential:基本認証の場合、実際には独自の資格情報の代わりにBasicCredentialsを使用する必要があります。基本的に、リクエストはBasicAuthProviderを通過します。プロバイダーはAuthorizationヘッダーを解析し、解析されたユーザー名とパスワードからBasicCredentialsオブジェクトを作成します。その処理が完了すると、BasicCredentialsSimpleAuthenticatorに渡されます。これらの資格情報を使用してユーザーを認証します。

SimplePrincipal:は基本的に、クライアントのauthorizeに使用するものです。認証プロセスから、プリンシパルを構築できます。プリンシパルは、後で承認するために使用されます(質問3を参照)。したがって、例は次のようになります

_import com.google.common.base.Optional;
import io.dropwizard.auth.AuthenticationException;
import io.dropwizard.auth.Authenticator;
import io.dropwizard.auth.basic.BasicCredentials;

public class SimpleAuthenticator implements Authenticator<BasicCredentials,
                                                          SimplePrincipal> {
    @Override
    public Optional<SimplePrincipal> authenticate(BasicCredentials credentials)
            throws AuthenticationException {

        // Note: this is horrible authentication. Normally we'd use some
        // service to identify the password from the user name.
        if (!"pass".equals(credentials.getPassword())) {
            throw new AuthenticationException("Boo Hooo!");
        }

        // from some user service get the roles for this user
        // I am explicitly setting it just for simplicity
        SimplePrincipal prince = new SimplePrincipal(credentials.getUsername());
        prince.getRoles().add(Roles.ADMIN);

        return Optional.fromNullable(prince);
    }
}
_

SimplePrincipalクラスを少し変更して、単純なRolesクラスを作成しました。

_public class SimplePrincipal {

    private String username;
    private List<String> roles = new ArrayList<>();

    public SimplePrincipal(String username) {
        this.username = username;
    }

    public List<String> getRoles() {
        return roles;
    }

    public boolean isUserInRole(String roleToCheck) {
        return roles.contains(roleToCheck);
    }

    public String getUsername() {
        return username;
    }
}

public class Roles {
    public static final String USER = "USER";
    public static final String ADMIN = "ADMIN";
    public static final String EMPLOYEE = "EMPLOYEE";
}
_

質問3:

承認のために追加のフィルターレイヤーを使用することを好む人もいますが、Dropwizardは、承認がリソースクラスで発生するという見解を持っているように見えます(私はそれをどこで読んだかを忘れましたが、私は信じています彼らの主張はテスト容易性です)。 SimplePrincialで作成したSimpleAuthenticatorで何が起こるかは、_@Auth_アノテーションを使用してリソースメソッドに注入できることです。 SimplePrincipalを使用して認証できます。何かのようなもの

_import dropwizard.sample.helloworld.security.Roles;
import dropwizard.sample.helloworld.security.SimplePrincipal;
import io.dropwizard.auth.Auth;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/simple")
public class SimpleResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getResponse(@Auth SimplePrincipal principal) {
        if (!principal.isUserInRole(Roles.ADMIN)) {
            throw new WebApplicationException(Response.Status.FORBIDDEN);
        }
        return Response.ok(
                "{\"Hello\": \"" + principal.getUsername() + "\"}").build();
    }
}
_

したがって、この構成ですべてをまとめます

_environment.jersey().register(new BasicAuthProvider<SimplePrincipal>(
                                            new SimpleAuthenticator(), 
                                            "Basic Example Realm")
);
_

以前に投稿したクライアント資格情報。リクエストを行うと、返されるはずです。

_{"Hello": "peeskillet"}
_

また、基本認証だけでは安全ではなく、SSL経由で行うことをお勧めします。


関連項目を参照:


更新

いくつかのこと:

  • Dropwizard 0.8.xでは、基本認証の構成が少し変更されました。 詳細はこちら をご覧ください。簡単な例は

    _SimpleAuthenticator auth = new SimpleAuthenticator();
    env.jersey().register(AuthFactory.binder(
            new BasicAuthFactory<>(auth,"Example Realm",SimplePrincipal.class)));
    _
  • AuthenticationExceptionの推奨される使用法については、上記のリンクを参照してください

37
Paul Samsotha