2017-09-06 11 views
0

1つのkeycloakクライアントが別のkeycloakクライアントと通信しているところで、KecloakRestTemplateを使用できます。ただし、最初のキークローキングクライアントにログインした場合、つまりクライアントID、クライアントシークレット、ユーザー名、パスワードをキークローキングサーバーに送信した場合にのみ機能します。最初のクライアントでユーザーとパスワードで認証されていない場合は、「認証された原則がないため、認証ヘッダーを設定できません」というメッセージが表示されます。しかし、最初のクライアント(Client Credential Grant)にサービスアカウントを使用するようにkeycloakを設定しました。したがって、ユーザー/パスワードを使用すべきではなく、クライアントID /秘密のみに頼るべきです。これはOAuth 2仕様のバグ/逸脱ですか?Keycloakスプリングセキュリティクライアントクレデンシャルの付与

答えて

0

私のマイクロサービスアーキテクチャベースのアプリケーションでは、私はユーザーアカウントとクライアントアカウントの両方を使用しています。私は春のセキュリティアダプターは、ユーザー関連のもの(私が使用しているバージョン、少なくとも2.2.1です)の世話をすると思います。私がやることは、別のRestTemplateを持って、クライアントとしてリソースにアクセスするために自分自身を処理するものです。一例として、

@Service 
public class RemoteAccessService{ 

    //Manages user access 
    private KeycloakRestTemplate userAccessRestTemplate; 

    //Manages client access 
    private RestTemplate clientAccessRestTemplate; 

    public RemoteAccessService(KeycloakRestTemplate userAccessRestTemplate, 
     @Qualifier("clientAccessRestTemplate") RestTemplate clientAccessRestTemplate;){ 

    } 

} 

その後、あなたはクライアントの認証を管理するために@ConfigurationクラスでRestTemplate豆を構築:もちろん

@Bean 
public RestTemplate clientAccessRestTemplate() { 
    RestTemplate template = new RestTemplate(); 
    template.getMessageConverters().add(new FormHttpMessageConverter()); 
    template.getMessageConverters().add(new MappingJackson2HttpMessageConverter()); 
    template.getInterceptors().add(new ClientHttpRequestInterceptor() { 

     @Override 
     public ClientHttpResponse intercept(HttpRequest request, byte[] body, 
       ClientHttpRequestExecution execution) throws IOException { 
      //Intercept each of the requests performed by this template 
      //and add the client access token in the Authorization header 
      HttpRequest wrapper = new HttpRequestWrapper(request); 
      if (clientAccessToken != null) { 
       wrapper.getHeaders().set("Authorization", 
         "Bearer " + clientAccessToken.getToken()); 
      } 
      return execution.execute(wrapper, body); 
     } 
    }); 
    return template; 
} 

を、あなたは「あなたのことを確認する必要がありますインターセプタ内に適切なclientAccessTokenがある場合は、そうでなければ401または403のコードを取得します。ここでは、OAuthでこれを実行する方法についてpostがあります(ユーザー/パスワードは必要なく、クライアントの認証情報は必要ありません)。

サイドクローズアダプタはいくつかの状況を管理するのに便利ですが、より強力な方法であるキークローキングのすべての機能にアクセスすることはできません。

0

KeycloakRestTemplateは、クライアントID、クライアントシークレット、ユーザー名、およびパスワードをKeycloakサーバーに送信します。私はクライアントIDと秘密だけを送りたいと思っていました。私はこれを行うOAuth2RestTemplateKeycloakClientCredentialsRestTemplateサブクラスを作成しました。 SpringブートでOAuth2サポートを使用して、クライアントクレデンシャルを付与します。 Keycloakプロパティはapplication.propertiesからも取得されます。また

import org.springframework.security.oauth2.client.OAuth2ClientContext; 
import org.springframework.security.oauth2.client.OAuth2RestTemplate; 
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; 

public class KeycloakClientCredentialsRestTemplate extends OAuth2RestTemplate { 

    public KeycloakClientCredentialsRestTemplate(OAuth2ProtectedResourceDetails resource, 
      OAuth2ClientContext context) { 
     super(resource, context); 
    } 

} 

import java.util.ArrayList; 
import java.util.List; 

import org.springframework.beans.factory.annotation.Value; 
import org.springframework.context.annotation.Bean; 
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext; 
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails; 
import org.springframework.security.oauth2.common.AuthenticationScheme; 
import org.springframework.stereotype.Service; 

@Service 
public class KeycloakClientCredentialsConfig { 

    @Value("${keycloak.realm}") 
    private String realm; 

    @Value("${keycloak.auth-server-url}") 
    private String authServerUrl; 

    @Value("${keycloak.resource}") 
    private String clientId; 

    @Value("${keycloak.credentials.secret}") 
    private String clientSecret; 

    @Bean 
    public KeycloakClientCredentialsRestTemplate createRestTemplate() { 
     return new KeycloakClientCredentialsRestTemplate(getClientCredentialsResourceDetails(), 
       new DefaultOAuth2ClientContext()); 
    } 

    private ClientCredentialsResourceDetails getClientCredentialsResourceDetails() { 
     String accessTokenUri = String.format("%s/realms/%s/protocol/openid-connect/token", 
      authServerUrl, realm); 
     List<String> scopes = new ArrayList<String>(0); // TODO introduce scopes 

     ClientCredentialsResourceDetails clientCredentialsResourceDetails = 
       new ClientCredentialsResourceDetails(); 

     clientCredentialsResourceDetails.setAccessTokenUri(accessTokenUri); 
     clientCredentialsResourceDetails.setAuthenticationScheme(AuthenticationScheme.header); 
     clientCredentialsResourceDetails.setClientId(clientId); 
     clientCredentialsResourceDetails.setClientSecret(clientSecret); 
     clientCredentialsResourceDetails.setScope(scopes); 

     return clientCredentialsResourceDetails; 
    } 

}