|
@@ -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.
|
|
|
|
|
|
* <<client-entity>>
|
|
@@ -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 <<client-entity,`Client`>> 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 <<authorization-entity,`Authorization`>> 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 <<authorization-consent-entity,`AuthorizationConsent`>> 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 <<create-jpa-entities,entities>> and <<create-spring-data-repositories,repositories>>, 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.
|
|
|
|
|
|
* <<registered-client-repository>>
|
|
@@ -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 <<client-repository,`ClientRepository`>> for persisting a <<client-entity,`Client`>> 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 <<authorization-repository,`AuthorizationRepository`>> for persisting an <<authorization-entity,`Authorization`>> 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 <<authorization-consent-repository,`AuthorizationConsentRepository`>> for persisting an <<authorization-consent-entity,`AuthorizationConsent`>> 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[]
|