Skip to content

Commit e15bb58

Browse files
committed
Store client settings and token settings in JSON fields
1 parent 4fe75bc commit e15bb58

File tree

3 files changed

+111
-52
lines changed

3 files changed

+111
-52
lines changed

oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/client/JdbcRegisteredClientRepository.java

+97-45
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package org.springframework.security.oauth2.server.authorization.client;
1717

18+
import com.fasterxml.jackson.core.JsonProcessingException;
19+
import com.fasterxml.jackson.databind.ObjectMapper;
1820
import org.springframework.jdbc.core.*;
1921
import org.springframework.jdbc.support.lob.DefaultLobHandler;
2022
import org.springframework.jdbc.support.lob.LobCreator;
@@ -54,18 +56,15 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
5456
+ "authorization_grant_types, "
5557
+ "redirect_uris, "
5658
+ "scopes, "
57-
+ "require_proof_key, "
58-
+ "require_user_consent, "
59-
+ "access_token_ttl, "
60-
+ "reuse_refresh_tokens, "
61-
+ "refresh_token_ttl";
59+
+ "client_settings,"
60+
+ "token_settings";
6261

6362
private static final String TABLE_NAME = "oauth2_registered_client";
6463

6564
private static final String LOAD_REGISTERED_CLIENT_SQL = "SELECT " + COLUMN_NAMES + " FROM " + TABLE_NAME + " WHERE ";
6665

6766
private static final String INSERT_REGISTERED_CLIENT_SQL = "INSERT INTO " + TABLE_NAME
68-
+ "(" + COLUMN_NAMES + ") values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
67+
+ "(" + COLUMN_NAMES + ") values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
6968

7069
private RowMapper<RegisteredClient> registeredClientRowMapper;
7170

@@ -75,9 +74,13 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
7574

7675
private final LobHandler lobHandler = new DefaultLobHandler();
7776

78-
public JdbcRegisteredClientRepository(JdbcOperations jdbcOperations) {
77+
private final ObjectMapper objectMapper;
78+
79+
public JdbcRegisteredClientRepository(JdbcOperations jdbcOperations, ObjectMapper objectMapper) {
7980
Assert.notNull(jdbcOperations, "jdbcOperations cannot be null");
81+
Assert.notNull(objectMapper, "objectMapper cannot be null");
8082
this.jdbcOperations = jdbcOperations;
83+
this.objectMapper = objectMapper;
8184
this.registeredClientRowMapper = new DefaultRegisteredClientRowMapper();
8285
this.registeredClientParametersMapper = new DefaultRegisteredClientParametersMapper();
8386
}
@@ -145,7 +148,7 @@ private RegisteredClient findBy(String condStr, Object...args) {
145148
return !lst.isEmpty() ? lst.get(0) : null;
146149
}
147150

148-
private static class DefaultRegisteredClientRowMapper implements RowMapper<RegisteredClient> {
151+
private class DefaultRegisteredClientRowMapper implements RowMapper<RegisteredClient> {
149152

150153
private final LobHandler lobHandler = new DefaultLobHandler();
151154

@@ -154,6 +157,7 @@ private Collection<String> parseList(String s) {
154157
}
155158

156159
@Override
160+
@SuppressWarnings("unchecked")
157161
public RegisteredClient mapRow(ResultSet rs, int rowNum) throws SQLException {
158162
Collection<String> scopes = parseList(rs.getString("scopes"));
159163
List<AuthorizationGrantType> authGrantTypes = parseList(rs.getString("authorization_grant_types"))
@@ -180,54 +184,102 @@ public RegisteredClient mapRow(ResultSet rs, int rowNum) throws SQLException {
180184
RegisteredClient rc = builder.build();
181185

182186
TokenSettings ts = rc.getTokenSettings();
183-
ts.accessTokenTimeToLive(Duration.ofMillis(rs.getLong("access_token_ttl")));
184-
ts.refreshTokenTimeToLive(Duration.ofMillis(rs.getLong("refresh_token_ttl")));
185-
ts.reuseRefreshTokens(rs.getBoolean("reuse_refresh_tokens"));
186-
187187
ClientSettings cs = rc.getClientSettings();
188-
cs.requireProofKey(rs.getBoolean("require_proof_key"));
189-
cs.requireUserConsent(rs.getBoolean("require_user_consent"));
188+
189+
try {
190+
String tokenSettingsJson = rs.getString("token_settings");
191+
if (tokenSettingsJson != null) {
192+
193+
Map<String, Object> m = JdbcRegisteredClientRepository.this.objectMapper.readValue(tokenSettingsJson, Map.class);
194+
195+
Number accessTokenTTL = (Number)m.get("access_token_ttl");
196+
if (accessTokenTTL != null) {
197+
ts.accessTokenTimeToLive(Duration.ofMillis(accessTokenTTL.longValue()));
198+
}
199+
200+
Number refreshTokenTTL = (Number)m.get("refresh_token_ttl");
201+
if (refreshTokenTTL != null) {
202+
ts.refreshTokenTimeToLive(Duration.ofMillis(refreshTokenTTL.longValue()));
203+
}
204+
205+
Boolean reuseRefreshTokens = (Boolean)m.get("reuse_refresh_tokens");
206+
if (reuseRefreshTokens != null) {
207+
ts.reuseRefreshTokens(reuseRefreshTokens);
208+
}
209+
}
210+
211+
String clientSettingsJson = rs.getString("client_settings");
212+
if (clientSettingsJson != null) {
213+
214+
Map<String, Object> m = JdbcRegisteredClientRepository.this.objectMapper.readValue(clientSettingsJson, Map.class);
215+
216+
Boolean requireProofKey = (Boolean)m.get("require_proof_key");
217+
if (requireProofKey != null) {
218+
cs.requireProofKey(requireProofKey);
219+
}
220+
221+
Boolean requireUserConsent = (Boolean)m.get("require_user_consent");
222+
if (requireUserConsent != null) {
223+
cs.requireUserConsent(requireUserConsent);
224+
}
225+
}
226+
227+
228+
} catch (JsonProcessingException e) {
229+
throw new IllegalArgumentException(e.getMessage(), e);
230+
}
190231

191232
return rc;
192233
}
193234
}
194235

195-
private static class DefaultRegisteredClientParametersMapper implements Function<RegisteredClient, List<SqlParameterValue>> {
236+
private class DefaultRegisteredClientParametersMapper implements Function<RegisteredClient, List<SqlParameterValue>> {
196237
@Override
197238
public List<SqlParameterValue> apply(RegisteredClient registeredClient) {
239+
try {
240+
List<String> clientAuthenticationMethodNames = new ArrayList<>(registeredClient.getClientAuthenticationMethods().size());
241+
for (ClientAuthenticationMethod clientAuthenticationMethod : registeredClient.getClientAuthenticationMethods()) {
242+
clientAuthenticationMethodNames.add(clientAuthenticationMethod.getValue());
243+
}
198244

199-
List<String> clientAuthenticationMethodNames = new ArrayList<>(registeredClient.getClientAuthenticationMethods().size());
200-
for (ClientAuthenticationMethod clientAuthenticationMethod : registeredClient.getClientAuthenticationMethods()) {
201-
clientAuthenticationMethodNames.add(clientAuthenticationMethod.getValue());
202-
}
245+
List<String> authorizationGrantTypeNames = new ArrayList<>(registeredClient.getAuthorizationGrantTypes().size());
246+
for (AuthorizationGrantType authorizationGrantType : registeredClient.getAuthorizationGrantTypes()) {
247+
authorizationGrantTypeNames.add(authorizationGrantType.getValue());
248+
}
203249

204-
List<String> authorizationGrantTypeNames = new ArrayList<>(registeredClient.getAuthorizationGrantTypes().size());
205-
for (AuthorizationGrantType authorizationGrantType : registeredClient.getAuthorizationGrantTypes()) {
206-
authorizationGrantTypeNames.add(authorizationGrantType.getValue());
250+
Instant issuedAt = registeredClient.getClientIdIssuedAt() != null ?
251+
registeredClient.getClientIdIssuedAt() : Instant.now();
252+
253+
Timestamp clientSecretExpiresAt = registeredClient.getClientSecretExpiresAt() != null ?
254+
Timestamp.from(registeredClient.getClientSecretExpiresAt()) : null;
255+
256+
Map<String,Object> clientSettings = new HashMap<>();
257+
clientSettings.put("require_proof_key", registeredClient.getClientSettings().requireProofKey());
258+
clientSettings.put("require_user_consent", registeredClient.getClientSettings().requireUserConsent());
259+
String clientSettingsJson = JdbcRegisteredClientRepository.this.objectMapper.writeValueAsString(clientSettings);
260+
261+
Map<String,Object> tokenSettings = new HashMap<>();
262+
tokenSettings.put("access_token_ttl", registeredClient.getTokenSettings().accessTokenTimeToLive().toMillis());
263+
tokenSettings.put("reuse_refresh_tokens", registeredClient.getTokenSettings().reuseRefreshTokens());
264+
tokenSettings.put("refresh_token_ttl", registeredClient.getTokenSettings().refreshTokenTimeToLive().toMillis());
265+
String tokenSettingsJson = JdbcRegisteredClientRepository.this.objectMapper.writeValueAsString(tokenSettings);
266+
267+
return Arrays.asList(
268+
new SqlParameterValue(Types.VARCHAR, registeredClient.getId()),
269+
new SqlParameterValue(Types.VARCHAR, registeredClient.getClientId()),
270+
new SqlParameterValue(Types.TIMESTAMP, Timestamp.from(issuedAt)),
271+
new SqlParameterValue(Types.BLOB, registeredClient.getClientSecret().getBytes(StandardCharsets.UTF_8)),
272+
new SqlParameterValue(Types.TIMESTAMP, clientSecretExpiresAt),
273+
new SqlParameterValue(Types.VARCHAR, registeredClient.getClientName()),
274+
new SqlParameterValue(Types.VARCHAR, String.join("|", clientAuthenticationMethodNames)),
275+
new SqlParameterValue(Types.VARCHAR, String.join("|", authorizationGrantTypeNames)),
276+
new SqlParameterValue(Types.VARCHAR, String.join("|", registeredClient.getRedirectUris())),
277+
new SqlParameterValue(Types.VARCHAR, String.join("|", registeredClient.getScopes())),
278+
new SqlParameterValue(Types.VARCHAR, clientSettingsJson),
279+
new SqlParameterValue(Types.VARCHAR, tokenSettingsJson));
280+
} catch (JsonProcessingException e) {
281+
throw new IllegalArgumentException(e.getMessage(), e);
207282
}
208-
209-
Instant issuedAt = registeredClient.getClientIdIssuedAt() != null ?
210-
registeredClient.getClientIdIssuedAt() : Instant.now();
211-
212-
Timestamp clientSecretExpiresAt = registeredClient.getClientSecretExpiresAt() != null ?
213-
Timestamp.from(registeredClient.getClientSecretExpiresAt()) : null;
214-
215-
return Arrays.asList(
216-
new SqlParameterValue(Types.VARCHAR, registeredClient.getId()),
217-
new SqlParameterValue(Types.VARCHAR, registeredClient.getClientId()),
218-
new SqlParameterValue(Types.TIMESTAMP, Timestamp.from(issuedAt)),
219-
new SqlParameterValue(Types.BLOB, registeredClient.getClientSecret().getBytes(StandardCharsets.UTF_8)),
220-
new SqlParameterValue(Types.TIMESTAMP, clientSecretExpiresAt),
221-
new SqlParameterValue(Types.VARCHAR, registeredClient.getClientName()),
222-
new SqlParameterValue(Types.VARCHAR, String.join("|", clientAuthenticationMethodNames)),
223-
new SqlParameterValue(Types.VARCHAR, String.join("|", authorizationGrantTypeNames)),
224-
new SqlParameterValue(Types.VARCHAR, String.join("|", registeredClient.getRedirectUris())),
225-
new SqlParameterValue(Types.VARCHAR, String.join("|", registeredClient.getScopes())),
226-
new SqlParameterValue(Types.BOOLEAN, registeredClient.getClientSettings().requireProofKey()),
227-
new SqlParameterValue(Types.BOOLEAN, registeredClient.getClientSettings().requireUserConsent()),
228-
new SqlParameterValue(Types.NUMERIC, registeredClient.getTokenSettings().accessTokenTimeToLive().toMillis()),
229-
new SqlParameterValue(Types.BOOLEAN, registeredClient.getTokenSettings().reuseRefreshTokens()),
230-
new SqlParameterValue(Types.NUMERIC, registeredClient.getTokenSettings().refreshTokenTimeToLive().toMillis()));
231283
}
232284
}
233285

oauth2-authorization-server/src/main/resources/org/springframework/security/oauth2/server/authorization/client/oauth2_registered_client.sql

+2-5
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@ CREATE TABLE oauth2_registered_client (
99
authorization_grant_types varchar(1000) NOT NULL,
1010
redirect_uris varchar(1000) NOT NULL,
1111
scopes varchar(1000) NOT NULL,
12-
require_proof_key boolean NOT NULL,
13-
require_user_consent boolean NOT NULL,
14-
access_token_ttl integer DEFAULT 300000 NOT NULL,
15-
reuse_refresh_tokens boolean DEFAULT true NOT NULL,
16-
refresh_token_ttl integer DEFAULT 600000 NOT NULL,
12+
client_settings varchar(1000) DEFAULT NULL,
13+
token_settings varchar(1000) DEFAULT NULL,
1714
PRIMARY KEY (id));

oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/client/JdbcRegisteredClientRepositoryTests.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.security.oauth2.server.authorization.client;
1717

18+
import com.fasterxml.jackson.databind.ObjectMapper;
1819
import org.junit.After;
1920
import org.junit.Before;
2021
import org.junit.Test;
@@ -70,7 +71,7 @@ public void setup() throws Exception {
7071
}
7172
}
7273

73-
this.clients = new JdbcRegisteredClientRepository(this.jdbc);
74+
this.clients = new JdbcRegisteredClientRepository(this.jdbc, new ObjectMapper());
7475
this.registration = TestRegisteredClients.registeredClient().build();
7576

7677
this.clients.save(this.registration);
@@ -86,11 +87,20 @@ public void destroyDatabase() {
8687
public void whenJdbcOperationsNullThenThrow() {
8788
// @formatter:off
8889
assertThatIllegalArgumentException()
89-
.isThrownBy(() -> new JdbcRegisteredClientRepository(null))
90+
.isThrownBy(() -> new JdbcRegisteredClientRepository(null, new ObjectMapper()))
9091
.withMessage("jdbcOperations cannot be null");
9192
// @formatter:on
9293
}
9394

95+
@Test
96+
public void whenObjectMapperNullThenThrow() {
97+
// @formatter:off
98+
assertThatIllegalArgumentException()
99+
.isThrownBy(() -> new JdbcRegisteredClientRepository(this.jdbc, null))
100+
.withMessage("objectMapper cannot be null");
101+
// @formatter:on
102+
}
103+
94104
@Test
95105
public void whenSetNullRegisteredClientRowMapperThenThrow() {
96106
// @formatter:off

0 commit comments

Comments
 (0)