Joe Grandja 3 лет назад
Родитель
Сommit
f8fdcd7ae9

+ 38 - 40
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/JdbcOAuth2AuthorizationService.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2020-2022 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -141,9 +141,10 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 
 	private static final String REMOVE_AUTHORIZATION_SQL = "DELETE FROM " + TABLE_NAME + " WHERE " + PK_FILTER;
 
+	private static int tokenColumnDataType;
+
 	private final JdbcOperations jdbcOperations;
 	private final LobHandler lobHandler;
-	private static int tokenColumnType;
 	private RowMapper<OAuth2Authorization> authorizationRowMapper;
 	private Function<OAuth2Authorization, List<SqlParameterValue>> authorizationParametersMapper;
 
@@ -172,15 +173,13 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 		Assert.notNull(lobHandler, "lobHandler cannot be null");
 		this.jdbcOperations = jdbcOperations;
 		this.lobHandler = lobHandler;
-		tokenColumnType = getColumnDataType(jdbcOperations, "access_token_value");
 		OAuth2AuthorizationRowMapper authorizationRowMapper = new OAuth2AuthorizationRowMapper(registeredClientRepository);
 		authorizationRowMapper.setLobHandler(lobHandler);
 		this.authorizationRowMapper = authorizationRowMapper;
-		OAuth2AuthorizationParametersMapper authorizationParametersMapper = new OAuth2AuthorizationParametersMapper();
-		this.authorizationParametersMapper = authorizationParametersMapper;
+		this.authorizationParametersMapper = new OAuth2AuthorizationParametersMapper();
+		tokenColumnDataType = getColumnDataType(jdbcOperations, "access_token_value", Types.BLOB);
 	}
 
-
 	@Override
 	public void save(OAuth2Authorization authorization) {
 		Assert.notNull(authorization, "authorization cannot be null");
@@ -259,10 +258,9 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 	}
 
 	private SqlParameterValue mapTokenToSqlParameter(String token) {
-		if (Types.BLOB == tokenColumnType) {
-			return new SqlParameterValue(Types.BLOB, token.getBytes(StandardCharsets.UTF_8));
-		}
-		return new SqlParameterValue(tokenColumnType, token);
+		return Types.BLOB == tokenColumnDataType ?
+				new SqlParameterValue(Types.BLOB, token.getBytes(StandardCharsets.UTF_8)) :
+				new SqlParameterValue(tokenColumnDataType, token);
 	}
 
 	private OAuth2Authorization findBy(String filter, List<SqlParameterValue> parameters) {
@@ -425,18 +423,16 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 
 		private String getTokenValue(ResultSet rs, String tokenColumn) throws SQLException {
 			String tokenValue = null;
-			if (Types.CLOB == tokenColumnType) {
+			if (Types.BLOB == tokenColumnDataType) {
+				byte[] tokenValueBytes = this.lobHandler.getBlobAsBytes(rs, tokenColumn);
+				if (tokenValueBytes != null) {
+					tokenValue = new String(tokenValueBytes, StandardCharsets.UTF_8);
+				}
+			} else if (Types.CLOB == tokenColumnDataType) {
 				tokenValue = this.lobHandler.getClobAsString(rs, tokenColumn);
-			}
-			if (Types.VARCHAR == tokenColumnType) {
+			} else {
 				tokenValue = rs.getString(tokenColumn);
 			}
-			if (Types.BLOB == tokenColumnType) {
-				byte[] tokenValueByte = this.lobHandler.getBlobAsBytes(rs, tokenColumn);
-				if (tokenValueByte != null) {
-					tokenValue = new String(tokenValueByte, StandardCharsets.UTF_8);
-				}
-			}
 			return tokenValue;
 		}
 
@@ -559,13 +555,12 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 				}
 				metadata = writeMap(token.getMetadata());
 			}
-			if (Types.BLOB == tokenColumnType && StringUtils.hasText(tokenValue)) {
-				byte[] tokenValueAsBytes = tokenValue.getBytes(StandardCharsets.UTF_8);
-				parameters.add(new SqlParameterValue(tokenColumnType, tokenValueAsBytes));
+			if (Types.BLOB == tokenColumnDataType && StringUtils.hasText(tokenValue)) {
+				byte[] tokenValueBytes = tokenValue.getBytes(StandardCharsets.UTF_8);
+				parameters.add(new SqlParameterValue(Types.BLOB, tokenValueBytes));
 			} else {
-				parameters.add(new SqlParameterValue(tokenColumnType, tokenValue));
+				parameters.add(new SqlParameterValue(tokenColumnDataType, tokenValue));
 			}
-
 			parameters.add(new SqlParameterValue(Types.TIMESTAMP, tokenIssuedAt));
 			parameters.add(new SqlParameterValue(Types.TIMESTAMP, tokenExpiresAt));
 			parameters.add(new SqlParameterValue(Types.VARCHAR, metadata));
@@ -582,22 +577,25 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 
 	}
 
-	private static int getColumnDataType(JdbcOperations jdbcOperations, String columnName){
-			return jdbcOperations.execute((ConnectionCallback<Integer>) con -> {
-				DatabaseMetaData databaseMetaData = con.getMetaData();
-				ResultSet rs = databaseMetaData.getColumns(null, null, TABLE_NAME, columnName);
-				if (rs.next()) {
-					return rs.getInt("DATA_TYPE");
-				}
-				// NOTE: When using HSQL: When a database object is created with one of the CREATE statements if the name is enclosed in double quotes, the exact name is used as the case-normal form.
-				// But if it is not enclosed in double quotes, the name is converted to uppercase and this uppercase version is stored in the database as the case-normal form
-				rs = databaseMetaData.getColumns(null, null, TABLE_NAME.toUpperCase(), columnName.toUpperCase());
-				if (rs.next()) {
-					return rs.getInt("DATA_TYPE");
-				}
-				return Types.NULL;
-			});
-		}
+	private static Integer getColumnDataType(JdbcOperations jdbcOperations, String columnName, int defaultDataType) {
+		return jdbcOperations.execute((ConnectionCallback<Integer>) conn -> {
+			DatabaseMetaData databaseMetaData = conn.getMetaData();
+			ResultSet rs = databaseMetaData.getColumns(null, null, TABLE_NAME, columnName);
+			if (rs.next()) {
+				return rs.getInt("DATA_TYPE");
+			}
+			// NOTE: (Applies to HSQL)
+			// When a database object is created with one of the CREATE statements or renamed with the ALTER statement,
+			// if the name is enclosed in double quotes, the exact name is used as the case-normal form.
+			// But if it is not enclosed in double quotes,
+			// the name is converted to uppercase and this uppercase version is stored in the database as the case-normal form.
+			rs = databaseMetaData.getColumns(null, null, TABLE_NAME.toUpperCase(), columnName.toUpperCase());
+			if (rs.next()) {
+				return rs.getInt("DATA_TYPE");
+			}
+			return defaultDataType;
+		});
+	}
 
 	private static final class LobCreatorArgumentPreparedStatementSetter extends ArgumentPreparedStatementSetter {
 		private final LobCreator lobCreator;

+ 0 - 42
oauth2-authorization-server/src/main/resources/org/springframework/security/oauth2/server/authorization/oauth2-authorization-schema-postgres.sql

@@ -1,42 +0,0 @@
-/*
- * Copyright 2020-2022 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-CREATE TABLE oauth2_authorization (
-    id varchar(100) NOT NULL,
-    registered_client_id varchar(100) NOT NULL,
-    principal_name varchar(200) NOT NULL,
-    authorization_grant_type varchar(100) NOT NULL,
-    attributes varchar(15000) DEFAULT NULL,
-    state varchar(500) DEFAULT NULL,
-    authorization_code_value text DEFAULT NULL,
-    authorization_code_issued_at timestamp DEFAULT NULL,
-    authorization_code_expires_at timestamp DEFAULT NULL,
-    authorization_code_metadata varchar(2000) DEFAULT NULL,
-    access_token_value text DEFAULT NULL,
-    access_token_issued_at timestamp DEFAULT NULL,
-    access_token_expires_at timestamp DEFAULT NULL,
-    access_token_metadata varchar(2000) DEFAULT NULL,
-    access_token_type varchar(100) DEFAULT NULL,
-    access_token_scopes varchar(1000) DEFAULT NULL,
-    oidc_id_token_value text DEFAULT NULL,
-    oidc_id_token_issued_at timestamp DEFAULT NULL,
-    oidc_id_token_expires_at timestamp DEFAULT NULL,
-    oidc_id_token_metadata varchar(2000) DEFAULT NULL,
-    refresh_token_value text DEFAULT NULL,
-    refresh_token_issued_at timestamp DEFAULT NULL,
-    refresh_token_expires_at timestamp DEFAULT NULL,
-    refresh_token_metadata varchar(2000) DEFAULT NULL,
-    PRIMARY KEY (id)
-);

+ 5 - 0
oauth2-authorization-server/src/main/resources/org/springframework/security/oauth2/server/authorization/oauth2-authorization-schema.sql

@@ -1,3 +1,8 @@
+/*
+IMPORTANT:
+    If using PostgreSQL, update ALL columns defined with 'blob' to 'text',
+    as PostgreSQL does not support the 'blob' data type.
+*/
 CREATE TABLE oauth2_authorization (
     id varchar(100) NOT NULL,
     registered_client_id varchar(100) NOT NULL,

+ 8 - 11
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/JdbcOAuth2AuthorizationServiceTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2020-2022 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -43,7 +43,6 @@ import org.springframework.jdbc.core.SqlParameterValue;
 import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
 import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
 import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
-import org.springframework.jdbc.support.lob.DefaultLobHandler;
 import org.springframework.security.oauth2.core.AbstractOAuth2Token;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
 import org.springframework.security.oauth2.core.OAuth2AccessToken;
@@ -76,7 +75,7 @@ import static org.mockito.Mockito.when;
 public class JdbcOAuth2AuthorizationServiceTests {
 	private static final String OAUTH2_AUTHORIZATION_SCHEMA_SQL_RESOURCE = "org/springframework/security/oauth2/server/authorization/oauth2-authorization-schema.sql";
 	private static final String CUSTOM_OAUTH2_AUTHORIZATION_SCHEMA_SQL_RESOURCE = "org/springframework/security/oauth2/server/authorization/custom-oauth2-authorization-schema.sql";
-	private static final String OAUTH2_AUTHORIZATION_SCHEMA_CLOB_COLUMN_TYPE_SQL_RESOURCE = "org/springframework/security/oauth2/server/authorization/custom-oauth2-authorization-schema-clob-data-type.sql";
+	private static final String OAUTH2_AUTHORIZATION_SCHEMA_CLOB_DATA_TYPE_SQL_RESOURCE = "org/springframework/security/oauth2/server/authorization/custom-oauth2-authorization-schema-clob-data-type.sql";
 	private static final OAuth2TokenType AUTHORIZATION_CODE_TOKEN_TYPE = new OAuth2TokenType(OAuth2ParameterNames.CODE);
 	private static final OAuth2TokenType STATE_TOKEN_TYPE = new OAuth2TokenType(OAuth2ParameterNames.STATE);
 	private static final String ID = "id";
@@ -417,12 +416,13 @@ public class JdbcOAuth2AuthorizationServiceTests {
 	}
 
 	@Test
-	public void tableDefinitionWhenClobSqlTypeThenUpdateAuthorization() {
-		EmbeddedDatabase db = createDb(OAUTH2_AUTHORIZATION_SCHEMA_CLOB_COLUMN_TYPE_SQL_RESOURCE);
-		OAuth2AuthorizationService authorizationService =
-				new JdbcOAuth2AuthorizationService(new JdbcTemplate(db), this.registeredClientRepository);
+	public void tableDefinitionWhenClobSqlTypeThenAuthorizationUpdated() {
 		when(this.registeredClientRepository.findById(eq(REGISTERED_CLIENT.getId())))
 				.thenReturn(REGISTERED_CLIENT);
+
+		EmbeddedDatabase db = createDb(OAUTH2_AUTHORIZATION_SCHEMA_CLOB_DATA_TYPE_SQL_RESOURCE);
+		OAuth2AuthorizationService authorizationService =
+				new JdbcOAuth2AuthorizationService(new JdbcTemplate(db), this.registeredClientRepository);
 		OAuth2Authorization originalAuthorization = OAuth2Authorization.withRegisteredClient(REGISTERED_CLIENT)
 				.id(ID)
 				.principalName(PRINCIPAL_NAME)
@@ -512,14 +512,11 @@ public class JdbcOAuth2AuthorizationServiceTests {
 
 		private CustomJdbcOAuth2AuthorizationService(JdbcOperations jdbcOperations,
 				RegisteredClientRepository registeredClientRepository) {
-			super(jdbcOperations, registeredClientRepository, new DefaultLobHandler());
+			super(jdbcOperations, registeredClientRepository);
 			setAuthorizationRowMapper(new CustomOAuth2AuthorizationRowMapper(registeredClientRepository));
 			setAuthorizationParametersMapper(new CustomOAuth2AuthorizationParametersMapper());
-
 		}
 
-
-
 		@Override
 		public void save(OAuth2Authorization authorization) {
 			List<SqlParameterValue> parameters = getAuthorizationParametersMapper().apply(authorization);

+ 1 - 16
oauth2-authorization-server/src/test/resources/org/springframework/security/oauth2/server/authorization/custom-oauth2-authorization-schema-clob-data-type.sql

@@ -1,24 +1,9 @@
-/*
- * Copyright 2020-2022 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
 CREATE TABLE oauth2_authorization (
     id varchar(100) NOT NULL,
     registered_client_id varchar(100) NOT NULL,
     principal_name varchar(200) NOT NULL,
     authorization_grant_type varchar(100) NOT NULL,
-    attributes varchar(15000) DEFAULT NULL,
+    attributes varchar(4000) DEFAULT NULL,
     state varchar(500) DEFAULT NULL,
     authorization_code_value clob DEFAULT NULL,
     authorization_code_issued_at timestamp DEFAULT NULL,