diff --git a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/Authorization.java b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/entity/authorization/Authorization.java similarity index 97% rename from docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/Authorization.java rename to docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/entity/authorization/Authorization.java index 515722f1..6b17decc 100644 --- a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/Authorization.java +++ b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/entity/authorization/Authorization.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package sample.jpa; +package sample.jpa.entity.authorization; import java.time.Instant; @@ -21,10 +21,6 @@ import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; -/** - * @author Steve Riesenberg - */ -// tag::class[] @Entity public class Authorization { @Id @@ -69,8 +65,7 @@ public class Authorization { @Column(length = 2000) private String oidcIdTokenClaims; - // getters and setters -// end::class[] + // @fold:on public String getId() { return id; } @@ -270,6 +265,5 @@ public class Authorization { public void setOidcIdTokenClaims(String idTokenClaims) { this.oidcIdTokenClaims = idTokenClaims; } -// tag::class[] + // @fold:off } -// end::class[] \ No newline at end of file diff --git a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/AuthorizationConsent.java b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/entity/authorizationConsent/AuthorizationConsent.java similarity index 90% rename from docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/AuthorizationConsent.java rename to docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/entity/authorizationConsent/AuthorizationConsent.java index 677d1099..8fb508da 100644 --- a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/AuthorizationConsent.java +++ b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/entity/authorizationConsent/AuthorizationConsent.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package sample.jpa; +package sample.jpa.entity.authorizationConsent; import java.io.Serializable; import java.util.Objects; @@ -23,10 +23,6 @@ import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.IdClass; -/** - * @author Steve Riesenberg - */ -// tag::class[] @Entity @IdClass(AuthorizationConsent.AuthorizationConsentId.class) public class AuthorizationConsent { @@ -37,8 +33,7 @@ public class AuthorizationConsent { @Column(length = 1000) private String authorities; - // getters and setters -// end::class[] + // @fold:on public String getRegisteredClientId() { return registeredClientId; } @@ -62,14 +57,13 @@ public class AuthorizationConsent { public void setAuthorities(String authorities) { this.authorities = authorities; } -// tag::class[] + // @fold:off public static class AuthorizationConsentId implements Serializable { private String registeredClientId; private String principalName; - // getters and setters -// end::class[] + // @fold:on public String getRegisteredClientId() { return registeredClientId; } @@ -85,10 +79,8 @@ public class AuthorizationConsent { public void setPrincipalName(String principalName) { this.principalName = principalName; } -// tag::class[] + // @fold:off - // equals and hashCode -// end::class[] @Override public boolean equals(Object o) { if (this == o) return true; @@ -101,7 +93,5 @@ public class AuthorizationConsent { public int hashCode() { return Objects.hash(registeredClientId, principalName); } -// tag::class[] } } -// end::class[] diff --git a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/Client.java b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/entity/client/Client.java similarity index 95% rename from docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/Client.java rename to docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/entity/client/Client.java index a2560e48..eb330237 100644 --- a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/Client.java +++ b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/entity/client/Client.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package sample.jpa; +package sample.jpa.entity.client; import java.time.Instant; @@ -21,10 +21,6 @@ import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; -/** - * @author Steve Riesenberg - */ -// tag::class[] @Entity public class Client { @Id @@ -47,8 +43,7 @@ public class Client { @Column(length = 2000) private String tokenSettings; - // getters and setters -// end::class[] + // @fold:on public String getId() { return id; } @@ -144,6 +139,5 @@ public class Client { public void setTokenSettings(String tokenSettings) { this.tokenSettings = tokenSettings; } -// tag::class[] + // @fold:off } -// end::class[] diff --git a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/AuthorizationRepository.java b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/repository/authorization/AuthorizationRepository.java similarity index 93% rename from docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/AuthorizationRepository.java rename to docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/repository/authorization/AuthorizationRepository.java index 55277fc7..d7dbd7a3 100644 --- a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/AuthorizationRepository.java +++ b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/repository/authorization/AuthorizationRepository.java @@ -13,19 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package sample.jpa; +package sample.jpa.repository.authorization; import java.util.Optional; +import sample.jpa.entity.authorization.Authorization; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -/** - * @author Steve Riesenberg - */ -// tag::class[] @Repository public interface AuthorizationRepository extends JpaRepository { Optional findByState(String state); @@ -39,4 +37,3 @@ public interface AuthorizationRepository extends JpaRepository findByStateOrAuthorizationCodeValueOrAccessTokenValueOrRefreshTokenValue(@Param("token") String token); } -// end::class[] diff --git a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/AuthorizationConsentRepository.java b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/repository/authorizationConsent/AuthorizationConsentRepository.java similarity index 90% rename from docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/AuthorizationConsentRepository.java rename to docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/repository/authorizationConsent/AuthorizationConsentRepository.java index 756446b2..669b33a2 100644 --- a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/AuthorizationConsentRepository.java +++ b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/repository/authorizationConsent/AuthorizationConsentRepository.java @@ -13,20 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package sample.jpa; +package sample.jpa.repository.authorizationConsent; import java.util.Optional; +import sample.jpa.entity.authorizationConsent.AuthorizationConsent; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -/** - * @author Steve Riesenberg - */ -// tag::class[] @Repository public interface AuthorizationConsentRepository extends JpaRepository { Optional findByRegisteredClientIdAndPrincipalName(String registeredClientId, String principalName); void deleteByRegisteredClientIdAndPrincipalName(String registeredClientId, String principalName); } -// end::class[] diff --git a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/ClientRepository.java b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/repository/client/ClientRepository.java similarity index 91% rename from docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/ClientRepository.java rename to docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/repository/client/ClientRepository.java index 62c6221f..1383a5ac 100644 --- a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/ClientRepository.java +++ b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/repository/client/ClientRepository.java @@ -13,19 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package sample.jpa; +package sample.jpa.repository.client; import java.util.Optional; +import sample.jpa.entity.client.Client; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -/** - * @author Steve Riesenberg - */ -// tag::class[] @Repository public interface ClientRepository extends JpaRepository { Optional findByClientId(String clientId); } -// end::class[] diff --git a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/JpaOAuth2AuthorizationService.java b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/service/authorization/JpaOAuth2AuthorizationService.java similarity index 98% rename from docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/JpaOAuth2AuthorizationService.java rename to docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/service/authorization/JpaOAuth2AuthorizationService.java index 564f4af7..52c08ac0 100644 --- a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/JpaOAuth2AuthorizationService.java +++ b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/service/authorization/JpaOAuth2AuthorizationService.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package sample.jpa; +package sample.jpa.service.authorization; import java.time.Instant; import java.util.List; @@ -24,6 +24,8 @@ import java.util.function.Consumer; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.ObjectMapper; +import sample.jpa.entity.authorization.Authorization; +import sample.jpa.repository.authorization.AuthorizationRepository; import org.springframework.dao.DataRetrievalFailureException; import org.springframework.security.jackson2.SecurityJackson2Modules; @@ -44,10 +46,6 @@ import org.springframework.stereotype.Component; import org.springframework.util.Assert; import org.springframework.util.StringUtils; -/** - * @author Steve Riesenberg - */ -// tag::class[] @Component public class JpaOAuth2AuthorizationService implements OAuth2AuthorizationService { private final AuthorizationRepository authorizationRepository; @@ -261,4 +259,3 @@ public class JpaOAuth2AuthorizationService implements OAuth2AuthorizationService return new AuthorizationGrantType(authorizationGrantType); // Custom authorization grant type } } -// end::class[] diff --git a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/JpaOAuth2AuthorizationConsentService.java b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/service/authorizationConsent/JpaOAuth2AuthorizationConsentService.java similarity index 95% rename from docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/JpaOAuth2AuthorizationConsentService.java rename to docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/service/authorizationConsent/JpaOAuth2AuthorizationConsentService.java index 3ea33b5c..1a588dce 100644 --- a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/JpaOAuth2AuthorizationConsentService.java +++ b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/service/authorizationConsent/JpaOAuth2AuthorizationConsentService.java @@ -13,11 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package sample.jpa; +package sample.jpa.service.authorizationConsent; import java.util.HashSet; import java.util.Set; +import sample.jpa.entity.authorizationConsent.AuthorizationConsent; +import sample.jpa.repository.authorizationConsent.AuthorizationConsentRepository; + import org.springframework.dao.DataRetrievalFailureException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -29,10 +32,6 @@ import org.springframework.stereotype.Component; import org.springframework.util.Assert; import org.springframework.util.StringUtils; -/** - * @author Steve Riesenberg - */ -// tag::class[] @Component public class JpaOAuth2AuthorizationConsentService implements OAuth2AuthorizationConsentService { private final AuthorizationConsentRepository authorizationConsentRepository; @@ -99,4 +98,3 @@ public class JpaOAuth2AuthorizationConsentService implements OAuth2Authorization return entity; } } -// end::class[] diff --git a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/JpaRegisteredClientRepository.java b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/service/client/JpaRegisteredClientRepository.java similarity index 98% rename from docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/JpaRegisteredClientRepository.java rename to docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/service/client/JpaRegisteredClientRepository.java index 4f4df188..f6b4865c 100644 --- a/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/JpaRegisteredClientRepository.java +++ b/docs/src/docs/asciidoc/examples/src/main/java/sample/jpa/service/client/JpaRegisteredClientRepository.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package sample.jpa; +package sample.jpa.service.client; import java.util.ArrayList; import java.util.List; @@ -23,6 +23,8 @@ import java.util.Set; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.ObjectMapper; +import sample.jpa.entity.client.Client; +import sample.jpa.repository.client.ClientRepository; import org.springframework.security.jackson2.SecurityJackson2Modules; import org.springframework.security.oauth2.core.AuthorizationGrantType; @@ -36,10 +38,6 @@ import org.springframework.stereotype.Component; import org.springframework.util.Assert; import org.springframework.util.StringUtils; -/** - * @author Steve Riesenberg - */ -// tag::class[] @Component public class JpaRegisteredClientRepository implements RegisteredClientRepository { private final ClientRepository clientRepository; @@ -172,4 +170,3 @@ public class JpaRegisteredClientRepository implements RegisteredClientRepository return new ClientAuthenticationMethod(clientAuthenticationMethod); // Custom client authentication method } } -// end::class[] diff --git a/docs/src/docs/asciidoc/examples/src/main/resources/oauth2-authorization-consent-schema.sql b/docs/src/docs/asciidoc/examples/src/main/resources/oauth2-authorization-consent-schema.sql deleted file mode 100644 index 4c115649..00000000 --- a/docs/src/docs/asciidoc/examples/src/main/resources/oauth2-authorization-consent-schema.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE authorizationConsent ( - registeredClientId varchar(255) NOT NULL, - principalName varchar(255) NOT NULL, - authorities varchar(1000) NOT NULL, - PRIMARY KEY (registeredClientId, principalName) -); diff --git a/docs/src/docs/asciidoc/examples/src/main/resources/oauth2-authorization-schema.sql b/docs/src/docs/asciidoc/examples/src/main/resources/oauth2-authorization-schema.sql deleted file mode 100644 index f3792062..00000000 --- a/docs/src/docs/asciidoc/examples/src/main/resources/oauth2-authorization-schema.sql +++ /dev/null @@ -1,28 +0,0 @@ -CREATE TABLE authorization ( - id varchar(255) NOT NULL, - registeredClientId varchar(255) NOT NULL, - principalName varchar(255) NOT NULL, - authorizationGrantType varchar(255) NOT NULL, - attributes varchar(4000) DEFAULT NULL, - state varchar(500) DEFAULT NULL, - authorizationCodeValue varchar(4000) DEFAULT NULL, - authorizationCodeIssuedAt timestamp DEFAULT NULL, - authorizationCodeExpiresAt timestamp DEFAULT NULL, - authorizationCodeMetadata varchar(2000) DEFAULT NULL, - accessTokenValue varchar(4000) DEFAULT NULL, - accessTokenIssuedAt timestamp DEFAULT NULL, - accessTokenExpiresAt timestamp DEFAULT NULL, - accessTokenMetadata varchar(2000) DEFAULT NULL, - accessTokenType varchar(255) DEFAULT NULL, - accessTokenScopes varchar(1000) DEFAULT NULL, - refreshTokenValue varchar(4000) DEFAULT NULL, - refreshTokenIssuedAt timestamp DEFAULT NULL, - refreshTokenExpiresAt timestamp DEFAULT NULL, - refreshTokenMetadata varchar(2000) DEFAULT NULL, - oidcIdTokenValue varchar(4000) DEFAULT NULL, - oidcIdTokenIssuedAt timestamp DEFAULT NULL, - oidcIdTokenExpiresAt timestamp DEFAULT NULL, - oidcIdTokenMetadata varchar(2000) DEFAULT NULL, - oidcIdTokenClaims varchar(2000) DEFAULT NULL, - PRIMARY KEY (id) -); diff --git a/docs/src/docs/asciidoc/examples/src/main/resources/oauth2-registered-client-schema.sql b/docs/src/docs/asciidoc/examples/src/main/resources/oauth2-registered-client-schema.sql deleted file mode 100644 index af1e69c8..00000000 --- a/docs/src/docs/asciidoc/examples/src/main/resources/oauth2-registered-client-schema.sql +++ /dev/null @@ -1,15 +0,0 @@ -CREATE TABLE client ( - id varchar(255) NOT NULL, - clientId varchar(255) NOT NULL, - clientIdIssuedAt timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL, - clientSecret varchar(255) DEFAULT NULL, - clientSecretExpiresAt timestamp DEFAULT NULL, - clientName varchar(255) NOT NULL, - clientAuthenticationMethods varchar(1000) NOT NULL, - authorizationGrantTypes varchar(1000) NOT NULL, - redirectUris varchar(1000) DEFAULT NULL, - scopes varchar(1000) NOT NULL, - clientSettings varchar(2000) NOT NULL, - tokenSettings varchar(2000) NOT NULL, - PRIMARY KEY (id) -); diff --git a/docs/src/docs/asciidoc/examples/src/test/java/sample/jpa/JpaTests.java b/docs/src/docs/asciidoc/examples/src/test/java/sample/jpa/JpaTests.java index 7e6cc842..9802893f 100644 --- a/docs/src/docs/asciidoc/examples/src/test/java/sample/jpa/JpaTests.java +++ b/docs/src/docs/asciidoc/examples/src/test/java/sample/jpa/JpaTests.java @@ -26,6 +26,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import sample.AuthorizationCodeGrantFlow; import sample.jose.TestJwks; +import sample.jpa.service.authorization.JpaOAuth2AuthorizationService; +import sample.jpa.service.authorizationConsent.JpaOAuth2AuthorizationConsentService; +import sample.jpa.service.client.JpaRegisteredClientRepository; import sample.test.SpringTestContext; import sample.test.SpringTestContextExtension; diff --git a/docs/src/docs/asciidoc/guides/how-to-jpa.adoc b/docs/src/docs/asciidoc/guides/how-to-jpa.adoc index 91a0d3b7..a4c980ed 100644 --- a/docs/src/docs/asciidoc/guides/how-to-jpa.adoc +++ b/docs/src/docs/asciidoc/guides/how-to-jpa.adoc @@ -2,7 +2,6 @@ = How-to: Implement core services with JPA :index-link: ../how-to.html :docs-dir: .. -:examples-dir: ../examples This guide shows how to implement the xref:{docs-dir}/core-model-components.adoc#core-model-components[core services] of xref:{docs-dir}/index.adoc#top[Spring Authorization Server] with JPA. The purpose of this guide is to provide a starting point for implementing these services yourself, with the intention that you can make modifications to suit your needs. @@ -18,7 +17,8 @@ The purpose of this guide is to provide a starting point for implementing these This guide provides a starting point for the data model and uses the simplest possible structure and data types. To come up with the initial schema, we begin by reviewing the xref:{docs-dir}/core-model-components.adoc#core-model-components[domain objects] used by the core services. -NOTE: Except for token, state, metadata, settings, and claims values, we use the JPA default column length of 255 for all columns. +[NOTE] +Except for token, state, metadata, settings, and claims values, we use the JPA default column length of 255 for all columns. In reality, the length and even type of columns you use may need to be customized. You are encouraged to experiment and test before deploying to production. @@ -35,7 +35,21 @@ The following listing shows the `client` schema. .Client Schema [source,sql] ---- -include::{examples-dir}/src/main/resources/oauth2-registered-client-schema.sql[] +CREATE TABLE client ( + id varchar(255) NOT NULL, + clientId varchar(255) NOT NULL, + clientIdIssuedAt timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL, + clientSecret varchar(255) DEFAULT NULL, + clientSecretExpiresAt timestamp DEFAULT NULL, + clientName varchar(255) NOT NULL, + clientAuthenticationMethods varchar(1000) NOT NULL, + authorizationGrantTypes varchar(1000) NOT NULL, + redirectUris varchar(1000) DEFAULT NULL, + scopes varchar(1000) NOT NULL, + clientSettings varchar(2000) NOT NULL, + tokenSettings varchar(2000) NOT NULL, + PRIMARY KEY (id) +); ---- [[authorization-schema]] @@ -44,7 +58,8 @@ include::{examples-dir}/src/main/resources/oauth2-registered-client-schema.sql[] The xref:{docs-dir}/core-model-components.adoc#oauth2-authorization[`OAuth2Authorization`] domain object is more complex and contains several multi-valued fields as well as numerous arbitrarily long token values, metadata, settings and claims values. The built-in JDBC implementation utilizes a flattened structure that prefers performance over normalization, which we adopt here as well. -CAUTION: It has been difficult to find a flattened database schema that works well in all cases and with all database vendors. +[CAUTION] +It has been difficult to find a flattened database schema that works well in all cases and with all database vendors. You may need to normalize or heavily alter the following schema for your needs. The following listing shows the `authorization` schema. @@ -52,7 +67,34 @@ The following listing shows the `authorization` schema. .Authorization Schema [source,sql] ---- -include::{examples-dir}/src/main/resources/oauth2-authorization-schema.sql[] +CREATE TABLE authorization ( + id varchar(255) NOT NULL, + registeredClientId varchar(255) NOT NULL, + principalName varchar(255) NOT NULL, + authorizationGrantType varchar(255) NOT NULL, + attributes varchar(4000) DEFAULT NULL, + state varchar(500) DEFAULT NULL, + authorizationCodeValue varchar(4000) DEFAULT NULL, + authorizationCodeIssuedAt timestamp DEFAULT NULL, + authorizationCodeExpiresAt timestamp DEFAULT NULL, + authorizationCodeMetadata varchar(2000) DEFAULT NULL, + accessTokenValue varchar(4000) DEFAULT NULL, + accessTokenIssuedAt timestamp DEFAULT NULL, + accessTokenExpiresAt timestamp DEFAULT NULL, + accessTokenMetadata varchar(2000) DEFAULT NULL, + accessTokenType varchar(255) DEFAULT NULL, + accessTokenScopes varchar(1000) DEFAULT NULL, + refreshTokenValue varchar(4000) DEFAULT NULL, + refreshTokenIssuedAt timestamp DEFAULT NULL, + refreshTokenExpiresAt timestamp DEFAULT NULL, + refreshTokenMetadata varchar(2000) DEFAULT NULL, + oidcIdTokenValue varchar(4000) DEFAULT NULL, + oidcIdTokenIssuedAt timestamp DEFAULT NULL, + oidcIdTokenExpiresAt timestamp DEFAULT NULL, + oidcIdTokenMetadata varchar(2000) DEFAULT NULL, + oidcIdTokenClaims varchar(2000) DEFAULT NULL, + PRIMARY KEY (id) +); ---- [[authorization-consent-schema]] @@ -64,7 +106,12 @@ The following listing shows the `authorizationConsent` schema. .Authorization Consent Schema [source,sql] ---- -include::{examples-dir}/src/main/resources/oauth2-authorization-consent-schema.sql[] +CREATE TABLE authorizationConsent ( + registeredClientId varchar(255) NOT NULL, + principalName varchar(255) NOT NULL, + authorities varchar(1000) NOT NULL, + PRIMARY KEY (registeredClientId, principalName) +); ---- [[create-jpa-entities]] @@ -72,7 +119,8 @@ include::{examples-dir}/src/main/resources/oauth2-authorization-consent-schema.s The preceding schema examples provide a reference for the structure of the entities we need to create. -NOTE: The following entities are minimally annotated and are just examples. +[NOTE] +The following entities are minimally annotated and are just examples. They allow the schema to be created dynamically and therefore do not require the above sql scripts to be executed manually. * <> @@ -84,33 +132,27 @@ They allow the schema to be created dynamically and therefore do not require the The following listing shows the `Client` entity, which is used to persist information mapped from the xref:{docs-dir}/core-model-components.adoc#registered-client[`RegisteredClient`] domain object. +[[sample.jpa.entity.client]] .Client Entity -[source,java] ----- -include::{examples-dir}/src/main/java/sample/jpa/Client.java[tag=class] ----- +include::code:Client[] [[authorization-entity]] === Authorization Entity The following listing shows the `Authorization` entity, which is used to persist information mapped from the xref:{docs-dir}/core-model-components.adoc#oauth2-authorization[`OAuth2Authorization`] domain object. +[[sample.jpa.entity.authorization]] .Authorization Entity -[source,java] ----- -include::{examples-dir}/src/main/java/sample/jpa/Authorization.java[tag=class] ----- +include::code:Authorization[] [[authorization-consent-entity]] === Authorization Consent Entity The following listing shows the `AuthorizationConsent` entity, which is used to persist information mapped from the xref:{docs-dir}/core-model-components.adoc#oauth2-authorization-consent[`OAuth2AuthorizationConsent`] domain object. +[[sample.jpa.entity.authorizationConsent]] .Authorization Consent Entity -[source,java] ----- -include::{examples-dir}/src/main/java/sample/jpa/AuthorizationConsent.java[tag=class] ----- +include::code:AuthorizationConsent[] [[create-spring-data-repositories]] == Create Spring Data repositories @@ -126,11 +168,9 @@ By closely examining the interfaces of each core service and reviewing the `Jdbc The following listing shows the `ClientRepository`, which is able to find a <> by the `id` and `clientId` fields. +[[sample.jpa.repository.client]] .Client Repository -[source,java] ----- -include::{examples-dir}/src/main/java/sample/jpa/ClientRepository.java[tag=class] ----- +include::code:ClientRepository[] [[authorization-repository]] === Authorization Repository @@ -138,22 +178,18 @@ include::{examples-dir}/src/main/java/sample/jpa/ClientRepository.java[tag=class The following listing shows the `AuthorizationRepository`, which is able to find an <> by the `id` field as well as the `state`, `authorizationCodeValue`, `accessTokenValue` and `refreshTokenValue` token fields. It also allows querying a combination of token fields. +[[sample.jpa.repository.authorization]] .Authorization Repository -[source,java] ----- -include::{examples-dir}/src/main/java/sample/jpa/AuthorizationRepository.java[tag=class] ----- +include::code:AuthorizationRepository[] [[authorization-consent-repository]] === Authorization Consent Repository The following listing shows the `AuthorizationConsentRepository`, which is able to find and delete an <> by the `registeredClientId` and `principalName` fields that form a composite primary key. +[[sample.jpa.repository.authorizationConsent]] .Authorization Consent Repository -[source,java] ----- -include::{examples-dir}/src/main/java/sample/jpa/AuthorizationConsentRepository.java[tag=class] ----- +include::code:AuthorizationConsentRepository[] [[implement-core-services]] == Implement core services @@ -161,7 +197,8 @@ include::{examples-dir}/src/main/java/sample/jpa/AuthorizationConsentRepository. With the above <> and <>, we can begin implementing the core services. By reviewing the `Jdbc` implementations, we can derive a minimal set of internal utilities for converting to and from string values for enumerations and reading and writing JSON data for attributes, settings, metadata and claims fields. -CAUTION: Keep in mind that writing JSON data to text columns with a fixed length has proven problematic with the `Jdbc` implementations. +[CAUTION] +Keep in mind that writing JSON data to text columns with a fixed length has proven problematic with the `Jdbc` implementations. While these examples continue to do so, you may need to split these fields out into a separate table or data store that supports arbitrarily long data values. * <> @@ -173,30 +210,24 @@ While these examples continue to do so, you may need to split these fields out i The following listing shows the `JpaRegisteredClientRepository`, which uses a <> for persisting a <> and maps to and from the xref:{docs-dir}/core-model-components.adoc#registered-client[`RegisteredClient`] domain object. +[[sample.jpa.service.client]] .`RegisteredClientRepository` Implementation -[source,java] ----- -include::{examples-dir}/src/main/java/sample/jpa/JpaRegisteredClientRepository.java[tag=class] ----- +include::code:JpaRegisteredClientRepository[] [[authorization-service]] === Authorization Service The following listing shows the `JpaOAuth2AuthorizationService`, which uses an <> for persisting an <> and maps to and from the xref:{docs-dir}/core-model-components.adoc#oauth2-authorization[`OAuth2Authorization`] domain object. +[[sample.jpa.service.authorization]] .`OAuth2AuthorizationService` Implementation -[source,java] ----- -include::{examples-dir}/src/main/java/sample/jpa/JpaOAuth2AuthorizationService.java[tag=class] ----- +include::code:JpaOAuth2AuthorizationService[] [[authorization-consent-service]] === Authorization Consent Service The following listing shows the `JpaOAuth2AuthorizationConsentService`, which uses an <> for persisting an <> and maps to and from the xref:{docs-dir}/core-model-components.adoc#oauth2-authorization-consent[`OAuth2AuthorizationConsent`] domain object. +[[sample.jpa.service.authorizationConsent]] .`OAuth2AuthorizationConsentService` Implementation -[source,java] ----- -include::{examples-dir}/src/main/java/sample/jpa/JpaOAuth2AuthorizationConsentService.java[tag=class] ----- +include::code:JpaOAuth2AuthorizationConsentService[]