keycloak
公開メンバ関数 | 静的公開変数類 | 静的非公開変数類 | 全メンバ一覧
org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator クラス
org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator の継承関係図
Inheritance graph
org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator 連携図
Collaboration graph

公開メンバ関数

void authenticateClient (ClientAuthenticationFlowContext context)
 
boolean isConfigurable ()
 
List< ProviderConfigPropertygetConfigPropertiesPerClient ()
 
Map< String, Object > getAdapterConfiguration (ClientModel client)
 
Set< String > getProtocolAuthenticatorMethods (String loginProtocol)
 
String getId ()
 
String getDisplayType ()
 
Requirement [] getRequirementChoices ()
 
String getHelpText ()
 
List< ProviderConfigPropertygetConfigProperties ()
 
ClientAuthenticator create ()
 
ClientAuthenticator create (KeycloakSession session)
 
void close ()
 
void init (Config.Scope config)
 
void postInit (KeycloakSessionFactory factory)
 
boolean isUserSetupAllowed ()
 
String getReferenceCategory ()
 
default int order ()
 

静的公開変数類

static final String PROVIDER_ID = "client-secret-jwt"
 
static final AuthenticationExecutionModel.Requirement [] REQUIREMENT_CHOICES
 

静的非公開変数類

static final Logger logger = Logger.getLogger(JWTClientSecretAuthenticator.class)
 

詳解

Client authentication based on JWT signed by client secret instead of private key . See specs for more details.

This is server side, which verifies JWT from client_assertion parameter, where the assertion was created on adapter side by org.keycloak.adapters.authentication.JWTClientSecretCredentialsProvider

著者
Takashi Norimatsu

関数詳解

◆ authenticateClient()

void org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator.authenticateClient ( ClientAuthenticationFlowContext  context)
inline

org.keycloak.authentication.ClientAuthenticatorを実装しています。

55  {
56  MultivaluedMap<String, String> params = context.getHttpRequest().getDecodedFormParameters();
57 
58  String clientAssertionType = params.getFirst(OAuth2Constants.CLIENT_ASSERTION_TYPE);
59  String clientAssertion = params.getFirst(OAuth2Constants.CLIENT_ASSERTION);
60 
61  if (clientAssertionType == null) {
62  Response challengeResponse = ClientAuthUtil.errorResponse(Response.Status.BAD_REQUEST.getStatusCode(), "invalid_client", "Parameter client_assertion_type is missing");
63  context.challenge(challengeResponse);
64  return;
65  }
66 
67  if (!clientAssertionType.equals(OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT)) {
68  Response challengeResponse = ClientAuthUtil.errorResponse(Response.Status.BAD_REQUEST.getStatusCode(), "invalid_client", "Parameter client_assertion_type has value '"
69  + clientAssertionType + "' but expected is '" + OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT + "'");
70  context.challenge(challengeResponse);
71  return;
72  }
73 
74  if (clientAssertion == null) {
75  Response challengeResponse = ClientAuthUtil.errorResponse(Response.Status.BAD_REQUEST.getStatusCode(), "invalid_client", "client_assertion parameter missing");
76  context.failure(AuthenticationFlowError.INVALID_CLIENT_CREDENTIALS, challengeResponse);
77  return;
78  }
79 
80  try {
81  JWSInput jws = new JWSInput(clientAssertion);
82  JsonWebToken token = jws.readJsonContent(JsonWebToken.class);
83 
84  RealmModel realm = context.getRealm();
85  String clientId = token.getSubject();
86  if (clientId == null) {
87  throw new RuntimeException("Can't identify client. Issuer missing on JWT token");
88  }
89 
90  context.getEvent().client(clientId);
91  ClientModel client = realm.getClientByClientId(clientId);
92  if (client == null) {
93  context.failure(AuthenticationFlowError.CLIENT_NOT_FOUND, null);
94  return;
95  } else {
96  context.setClient(client);
97  }
98 
99  if (!client.isEnabled()) {
100  context.failure(AuthenticationFlowError.CLIENT_DISABLED, null);
101  return;
102  }
103 
104  String clientSecretString = client.getSecret();
105  if (clientSecretString == null) {
106  context.failure(AuthenticationFlowError.INVALID_CLIENT_CREDENTIALS, null);
107  return;
108  }
109 
110  // Get client secret and validate signature
111  // According to <a href="http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication">OIDC's client authentication spec</a>,
112  // The HMAC (Hash-based Message Authentication Code) is calculated using the octets of the UTF-8 representation of the client_secret as the shared key.
113  // Use "HmacSHA256" consulting <a href="https://docs.oracle.com/javase/jp/8/docs/api/javax/crypto/Mac.html">java8 api</a>.
114  SecretKey clientSecret = new SecretKeySpec(clientSecretString.getBytes("UTF-8"), "HmacSHA256");
115 
116  boolean signatureValid;
117  try {
118  signatureValid = HMACProvider.verify(jws, clientSecret);
119  } catch (RuntimeException e) {
120  Throwable cause = e.getCause() != null ? e.getCause() : e;
121  throw new RuntimeException("Signature on JWT token by client secret failed validation", cause);
122  }
123  if (!signatureValid) {
124  throw new RuntimeException("Signature on JWT token by client secret failed validation");
125  }
126  // According to <a href="http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication">OIDC's client authentication spec</a>,
127  // JWT contents and verification in client_secret_jwt is the same as in private_key_jwt
128 
129  // Allow both "issuer" or "token-endpoint" as audience
130  String issuerUrl = Urls.realmIssuer(context.getUriInfo().getBaseUri(), realm.getName());
131  String tokenUrl = OIDCLoginProtocolService.tokenUrl(context.getUriInfo().getBaseUriBuilder()).build(realm.getName()).toString();
132  if (!token.hasAudience(issuerUrl) && !token.hasAudience(tokenUrl)) {
133  throw new RuntimeException("Token audience doesn't match domain. Realm issuer is '" + issuerUrl + "' but audience from token is '" + Arrays.asList(token.getAudience()).toString() + "'");
134  }
135 
136  if (!token.isActive()) {
137  throw new RuntimeException("Token is not active");
138  }
139 
140  // KEYCLOAK-2986, token-timeout or token-expiration in keycloak.json might not be used
141  if (token.getExpiration() == 0 && token.getIssuedAt() + 10 < Time.currentTime()) {
142  throw new RuntimeException("Token is not active");
143  }
144 
145  context.success();
146  } catch (Exception e) {
147  ServicesLogger.LOGGER.errorValidatingAssertion(e);
148  Response challengeResponse = ClientAuthUtil.errorResponse(Response.Status.BAD_REQUEST.getStatusCode(), "unauthorized_client", "Client authentication with client secret signed JWT failed: " + e.getMessage());
149  context.failure(AuthenticationFlowError.INVALID_CLIENT_CREDENTIALS, challengeResponse);
150  }
151  }

◆ close()

void org.keycloak.authentication.authenticators.client.AbstractClientAuthenticator.close ( )
inlineinherited

org.keycloak.provider.Providerを実装しています。

37  {
38 
39  }

◆ create() [1/2]

ClientAuthenticator org.keycloak.authentication.authenticators.client.AbstractClientAuthenticator.create ( )
inlineinherited

org.keycloak.authentication.ClientAuthenticatorFactoryを実装しています。

32  {
33  return this;
34  }

◆ create() [2/2]

ClientAuthenticator org.keycloak.authentication.authenticators.client.AbstractClientAuthenticator.create ( KeycloakSession  session)
inlineinherited

org.keycloak.provider.ProviderFactory< T extends Provider >を実装しています。

42  {
43  return this;
44  }

◆ getAdapterConfiguration()

Map<String, Object> org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator.getAdapterConfiguration ( ClientModel  client)
inline

org.keycloak.authentication.ClientAuthenticatorFactoryを実装しています。

165  {
166  // e.g.
167  // "credentials": {
168  // "secret-jwt": {
169  // "secret": "234234-234234-234234"
170  // }
171  // }
172  Map<String, Object> props = new HashMap<>();
173  props.put("secret", client.getSecret());
174 
175  Map<String, Object> config = new HashMap<>();
176  config.put("secret-jwt", props);
177  return config;
178  }

◆ getConfigProperties()

List<ProviderConfigProperty> org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator.getConfigProperties ( )
inline

org.keycloak.provider.ConfiguredProviderを実装しています。

213  {
214  return new LinkedList<>();
215  }

◆ getConfigPropertiesPerClient()

List<ProviderConfigProperty> org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator.getConfigPropertiesPerClient ( )
inline

org.keycloak.authentication.ClientAuthenticatorFactoryを実装しています。

159  {
160  // This impl doesn't use generic screen in admin console, but has its own screen. So no need to return anything here
161  return Collections.emptyList();
162  }

◆ getDisplayType()

String org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator.getDisplayType ( )
inline

org.keycloak.authentication.ConfigurableAuthenticatorFactoryを実装しています。

197  {
198  return "Signed Jwt with Client Secret";
199  }

◆ getHelpText()

String org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator.getHelpText ( )
inline

org.keycloak.provider.ConfiguredProviderを実装しています。

207  {
208  return "Validates client based on signed JWT issued by client and signed with the Client Secret";
209 
210  }

◆ getId()

String org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator.getId ( )
inline

org.keycloak.provider.ProviderFactory< T extends Provider >を実装しています。

192  {
193  return PROVIDER_ID;
194  }
static final String PROVIDER_ID
Definition: JWTClientSecretAuthenticator.java:47

◆ getProtocolAuthenticatorMethods()

Set<String> org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator.getProtocolAuthenticatorMethods ( String  loginProtocol)
inline

org.keycloak.authentication.ClientAuthenticatorFactoryを実装しています。

181  {
182  if (loginProtocol.equals(OIDCLoginProtocol.LOGIN_PROTOCOL)) {
183  Set<String> results = new HashSet<>();
184  results.add(OIDCLoginProtocol.CLIENT_SECRET_JWT);
185  return results;
186  } else {
187  return Collections.emptySet();
188  }
189  }

◆ getReferenceCategory()

String org.keycloak.authentication.authenticators.client.AbstractClientAuthenticator.getReferenceCategory ( )
inlineinherited

org.keycloak.authentication.ConfigurableAuthenticatorFactoryを実装しています。

62  {
63  return null;
64  }

◆ getRequirementChoices()

Requirement [] org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator.getRequirementChoices ( )
inline

org.keycloak.authentication.ConfigurableAuthenticatorFactoryを実装しています。

202  {
203  return REQUIREMENT_CHOICES;
204  }
static final AuthenticationExecutionModel.Requirement [] REQUIREMENT_CHOICES
Definition: JWTClientSecretAuthenticator.java:49

◆ init()

void org.keycloak.authentication.authenticators.client.AbstractClientAuthenticator.init ( Config.Scope  config)
inlineinherited

org.keycloak.provider.ProviderFactory< T extends Provider >を実装しています。

47  {
48 
49  }

◆ isConfigurable()

boolean org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator.isConfigurable ( )
inline

org.keycloak.authentication.ClientAuthenticatorFactoryを実装しています。

154  {
155  return false;
156  }

◆ isUserSetupAllowed()

boolean org.keycloak.authentication.authenticators.client.AbstractClientAuthenticator.isUserSetupAllowed ( )
inlineinherited

org.keycloak.authentication.ConfigurableAuthenticatorFactoryを実装しています。

57  {
58  return false;
59  }

◆ order()

default int org.keycloak.provider.ProviderFactory< T extends Provider >.order ( )
inlineinherited

◆ postInit()

void org.keycloak.authentication.authenticators.client.AbstractClientAuthenticator.postInit ( KeycloakSessionFactory  factory)
inlineinherited

org.keycloak.provider.ProviderFactory< T extends Provider >を実装しています。

52  {
53 
54  }

メンバ詳解

◆ logger

final Logger org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator.logger = Logger.getLogger(JWTClientSecretAuthenticator.class)
staticprivate

◆ PROVIDER_ID

final String org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator.PROVIDER_ID = "client-secret-jwt"
static

◆ REQUIREMENT_CHOICES

final AuthenticationExecutionModel.Requirement [] org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator.REQUIREMENT_CHOICES
static
初期値:
= {
AuthenticationExecutionModel.Requirement.ALTERNATIVE,
AuthenticationExecutionModel.Requirement.DISABLED
}

このクラス詳解は次のファイルから抽出されました: