SpringによるRESTful認証

問題: 私たちは、機密情報を含むSpring MVCベースのRESTful APIを持っています。APIは安全であるべきですが、各リクエストでユーザーの認証情報(ユーザー/パスのコンボ)を送信することは望ましくありません。RESTのガイドライン(および社内のビジネス要件)により、サーバーはステートレスのままでなければなりません。APIはマッシュアップ方式で他のサーバーから消費される。

要件:

  • クライアントが .../authenticate (保護されていないURL) に認証情報とともにリクエストを行う。サーバーは、今後のリクエストを検証するために十分な情報を含む安全なトークンを返し、ステートレスの状態を維持する。これはおそらくSpring Security's Remember-Me Tokenと同じ情報で構成されるでしょう。

  • クライアントは様々な(保護された)URLに対して、前回取得したトークンをクエリパラメータ(または、あまり望ましくないですが、HTTPリクエストヘッダ)として付加して、それ以降のリクエストを行うことができます。

  • クライアントがクッキーを保存することは期待できない。

  • 私たちはすでにSpringを使っているので、ソリューションはSpring Securityを利用する必要があります。

この問題を解決するために、私たちは壁に頭を打ち付けています。

上記のシナリオがあるとして、あなたはこの特別なニーズをどのように解決することができますか?

質問へのコメント (8)
ソリューション

私たちは、OPに記載されたとおりにこれを動作させることができました。そして、うまくいけば、他の誰かがこの解決策を利用することができます。以下は、私たちが行ったことです。

セキュリティコンテキストをこのように設定します。











見ての通り、カスタムの AuthenticationEntryPoint を作成しました。これは基本的に、リクエストが AuthenticationTokenProcessingFilter によるフィルターチェーンで認証されなかった場合、 401 Unauthorized を返すだけです。

CustomAuthenticationEntryPoint:

public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException authException) throws IOException, ServletException {
        response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized: Authentication token was either missing or invalid." );
    }
}

AuthenticationTokenProcessingFilter:

public class AuthenticationTokenProcessingFilter extends GenericFilterBean {

    @Autowired UserService userService;
    @Autowired TokenUtils tokenUtils;
    AuthenticationManager authManager;

    public AuthenticationTokenProcessingFilter(AuthenticationManager authManager) {
        this.authManager = authManager;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        @SuppressWarnings("unchecked")
        Map parms = request.getParameterMap();

        if(parms.containsKey("token")) {
            String token = parms.get("token")[0]; // grab the first "token" parameter

            // validate the token
            if (tokenUtils.validate(token)) {
                // determine the user based on the (already validated) token
                UserDetails userDetails = tokenUtils.getUserFromToken(token);
                // build an Authentication object with the user's info
                UsernamePasswordAuthenticationToken authentication = 
                        new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails((HttpServletRequest) request));
                // set the authentication into the SecurityContext
                SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(authentication));         
            }
        }
        // continue thru the filter chain
        chain.doFilter(request, response);
    }
}

明らかに、TokenUtils` は非公開の(そして非常に特定的な)コードを含んでおり、容易に共有することはできません'。以下はそのインターフェイスです。

public interface TokenUtils {
    String getToken(UserDetails userDetails);
    String getToken(UserDetails userDetails, Long expiration);
    boolean validate(String token);
    UserDetails getUserFromToken(String token);
}

これで良いスタートが切れると思います。ハッピーコーディング。)

解説 (32)

ダイジェストアクセス認証]1を検討してみてはいかがでしょうか。 基本的には以下のようなプロトコルです。

    クライアントからリクエストされる。 サーバは一意のnonce文字列で応答する。
  1. クライアントはユーザー名とパスワード(と他の値)をnonceとmd5ハッシュ化したものを提供する; このハッシュはHA1として知られている; /li> サーバはクライアントの身元を確認し、要求された資料を提供することができます。
  2. nonce を使った通信は、サーバーが新しい nonce を供給するまで継続できる(リプレイ攻撃を排除するためにカウンターを使用する)

この通信はすべてヘッダを介して行われます。jmort253が指摘するように、これは一般に、URLパラメータで機密事項を通信するよりも安全です。

ダイジェストアクセス認証は、Spring Securityでサポートされています。 ドキュメントによると、クライアントの平文パスワードにアクセスできなければなりませんが、クライアントのHA1ハッシュを持っていれば認証に成功する]3ことに注意してください。

解説 (2)

情報を運ぶトークンについては、JSON Web Tokens (http://jwt.io) が素晴らしい技術である。その主なコンセプトは、トークンに情報要素(クレーム)を埋め込み、検証側がそのクレームが本当に信頼できるかを検証できるように、トークン全体に署名を行うことです。

私はこのJava実装を使っています: https://bitbucket.org/b_c/jose4j/wiki/Home

Springのモジュール(spring-security-jwt)もありますが、何をサポートしているかは調べてません。

解説 (0)

JSON WebTokensでOAuthを使い始めてみませんか。

http://projects.spring.io/spring-security-oauth/

OAuth2は、標準化された承認プロトコル/フレームワークです。 公式OAuth2 仕様に従って:

詳細ここを見つけることができます。

解説 (0)