Add "How-to: Implement core services with JPA"
This commit is contained in:
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
package sample.jpa;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
// tag::class[]
|
||||
@Entity
|
||||
public class Authorization {
|
||||
@Id
|
||||
private String id;
|
||||
private String registeredClientId;
|
||||
private String principalName;
|
||||
private String authorizationGrantType;
|
||||
@Column(length = 4000)
|
||||
private String attributes;
|
||||
@Column(length = 500)
|
||||
private String state;
|
||||
|
||||
@Column(length = 4000)
|
||||
private String authorizationCodeValue;
|
||||
private Instant authorizationCodeIssuedAt;
|
||||
private Instant authorizationCodeExpiresAt;
|
||||
private String authorizationCodeMetadata;
|
||||
|
||||
@Column(length = 4000)
|
||||
private String accessTokenValue;
|
||||
private Instant accessTokenIssuedAt;
|
||||
private Instant accessTokenExpiresAt;
|
||||
@Column(length = 2000)
|
||||
private String accessTokenMetadata;
|
||||
private String accessTokenType;
|
||||
@Column(length = 1000)
|
||||
private String accessTokenScopes;
|
||||
|
||||
@Column(length = 4000)
|
||||
private String refreshTokenValue;
|
||||
private Instant refreshTokenIssuedAt;
|
||||
private Instant refreshTokenExpiresAt;
|
||||
@Column(length = 2000)
|
||||
private String refreshTokenMetadata;
|
||||
|
||||
@Column(length = 4000)
|
||||
private String oidcIdTokenValue;
|
||||
private Instant oidcIdTokenIssuedAt;
|
||||
private Instant oidcIdTokenExpiresAt;
|
||||
@Column(length = 2000)
|
||||
private String oidcIdTokenMetadata;
|
||||
@Column(length = 2000)
|
||||
private String oidcIdTokenClaims;
|
||||
|
||||
// getters and setters
|
||||
// end::class[]
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getRegisteredClientId() {
|
||||
return registeredClientId;
|
||||
}
|
||||
|
||||
public void setRegisteredClientId(String registeredClientId) {
|
||||
this.registeredClientId = registeredClientId;
|
||||
}
|
||||
|
||||
public String getPrincipalName() {
|
||||
return principalName;
|
||||
}
|
||||
|
||||
public void setPrincipalName(String principalName) {
|
||||
this.principalName = principalName;
|
||||
}
|
||||
|
||||
public String getAuthorizationGrantType() {
|
||||
return authorizationGrantType;
|
||||
}
|
||||
|
||||
public void setAuthorizationGrantType(String authorizationGrantType) {
|
||||
this.authorizationGrantType = authorizationGrantType;
|
||||
}
|
||||
|
||||
public String getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public void setAttributes(String attributes) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public String getAuthorizationCodeValue() {
|
||||
return authorizationCodeValue;
|
||||
}
|
||||
|
||||
public void setAuthorizationCodeValue(String authorizationCode) {
|
||||
this.authorizationCodeValue = authorizationCode;
|
||||
}
|
||||
|
||||
public Instant getAuthorizationCodeIssuedAt() {
|
||||
return authorizationCodeIssuedAt;
|
||||
}
|
||||
|
||||
public void setAuthorizationCodeIssuedAt(Instant authorizationCodeIssuedAt) {
|
||||
this.authorizationCodeIssuedAt = authorizationCodeIssuedAt;
|
||||
}
|
||||
|
||||
public Instant getAuthorizationCodeExpiresAt() {
|
||||
return authorizationCodeExpiresAt;
|
||||
}
|
||||
|
||||
public void setAuthorizationCodeExpiresAt(Instant authorizationCodeExpiresAt) {
|
||||
this.authorizationCodeExpiresAt = authorizationCodeExpiresAt;
|
||||
}
|
||||
|
||||
public String getAuthorizationCodeMetadata() {
|
||||
return authorizationCodeMetadata;
|
||||
}
|
||||
|
||||
public void setAuthorizationCodeMetadata(String authorizationCodeMetadata) {
|
||||
this.authorizationCodeMetadata = authorizationCodeMetadata;
|
||||
}
|
||||
|
||||
public String getAccessTokenValue() {
|
||||
return accessTokenValue;
|
||||
}
|
||||
|
||||
public void setAccessTokenValue(String accessToken) {
|
||||
this.accessTokenValue = accessToken;
|
||||
}
|
||||
|
||||
public Instant getAccessTokenIssuedAt() {
|
||||
return accessTokenIssuedAt;
|
||||
}
|
||||
|
||||
public void setAccessTokenIssuedAt(Instant accessTokenIssuedAt) {
|
||||
this.accessTokenIssuedAt = accessTokenIssuedAt;
|
||||
}
|
||||
|
||||
public Instant getAccessTokenExpiresAt() {
|
||||
return accessTokenExpiresAt;
|
||||
}
|
||||
|
||||
public void setAccessTokenExpiresAt(Instant accessTokenExpiresAt) {
|
||||
this.accessTokenExpiresAt = accessTokenExpiresAt;
|
||||
}
|
||||
|
||||
public String getAccessTokenMetadata() {
|
||||
return accessTokenMetadata;
|
||||
}
|
||||
|
||||
public void setAccessTokenMetadata(String accessTokenMetadata) {
|
||||
this.accessTokenMetadata = accessTokenMetadata;
|
||||
}
|
||||
|
||||
public String getAccessTokenType() {
|
||||
return accessTokenType;
|
||||
}
|
||||
|
||||
public void setAccessTokenType(String accessTokenType) {
|
||||
this.accessTokenType = accessTokenType;
|
||||
}
|
||||
|
||||
public String getAccessTokenScopes() {
|
||||
return accessTokenScopes;
|
||||
}
|
||||
|
||||
public void setAccessTokenScopes(String accessTokenScopes) {
|
||||
this.accessTokenScopes = accessTokenScopes;
|
||||
}
|
||||
|
||||
public String getRefreshTokenValue() {
|
||||
return refreshTokenValue;
|
||||
}
|
||||
|
||||
public void setRefreshTokenValue(String refreshToken) {
|
||||
this.refreshTokenValue = refreshToken;
|
||||
}
|
||||
|
||||
public Instant getRefreshTokenIssuedAt() {
|
||||
return refreshTokenIssuedAt;
|
||||
}
|
||||
|
||||
public void setRefreshTokenIssuedAt(Instant refreshTokenIssuedAt) {
|
||||
this.refreshTokenIssuedAt = refreshTokenIssuedAt;
|
||||
}
|
||||
|
||||
public Instant getRefreshTokenExpiresAt() {
|
||||
return refreshTokenExpiresAt;
|
||||
}
|
||||
|
||||
public void setRefreshTokenExpiresAt(Instant refreshTokenExpiresAt) {
|
||||
this.refreshTokenExpiresAt = refreshTokenExpiresAt;
|
||||
}
|
||||
|
||||
public String getRefreshTokenMetadata() {
|
||||
return refreshTokenMetadata;
|
||||
}
|
||||
|
||||
public void setRefreshTokenMetadata(String refreshTokenMetadata) {
|
||||
this.refreshTokenMetadata = refreshTokenMetadata;
|
||||
}
|
||||
|
||||
public String getOidcIdTokenValue() {
|
||||
return oidcIdTokenValue;
|
||||
}
|
||||
|
||||
public void setOidcIdTokenValue(String idToken) {
|
||||
this.oidcIdTokenValue = idToken;
|
||||
}
|
||||
|
||||
public Instant getOidcIdTokenIssuedAt() {
|
||||
return oidcIdTokenIssuedAt;
|
||||
}
|
||||
|
||||
public void setOidcIdTokenIssuedAt(Instant idTokenIssuedAt) {
|
||||
this.oidcIdTokenIssuedAt = idTokenIssuedAt;
|
||||
}
|
||||
|
||||
public Instant getOidcIdTokenExpiresAt() {
|
||||
return oidcIdTokenExpiresAt;
|
||||
}
|
||||
|
||||
public void setOidcIdTokenExpiresAt(Instant idTokenExpiresAt) {
|
||||
this.oidcIdTokenExpiresAt = idTokenExpiresAt;
|
||||
}
|
||||
|
||||
public String getOidcIdTokenMetadata() {
|
||||
return oidcIdTokenMetadata;
|
||||
}
|
||||
|
||||
public void setOidcIdTokenMetadata(String idTokenMetadata) {
|
||||
this.oidcIdTokenMetadata = idTokenMetadata;
|
||||
}
|
||||
|
||||
public String getOidcIdTokenClaims() {
|
||||
return oidcIdTokenClaims;
|
||||
}
|
||||
|
||||
public void setOidcIdTokenClaims(String idTokenClaims) {
|
||||
this.oidcIdTokenClaims = idTokenClaims;
|
||||
}
|
||||
// tag::class[]
|
||||
}
|
||||
// end::class[]
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
package sample.jpa;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.persistence.Column;
|
||||
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 {
|
||||
@Id
|
||||
private String registeredClientId;
|
||||
@Id
|
||||
private String principalName;
|
||||
@Column(length = 1000)
|
||||
private String authorities;
|
||||
|
||||
// getters and setters
|
||||
// end::class[]
|
||||
public String getRegisteredClientId() {
|
||||
return registeredClientId;
|
||||
}
|
||||
|
||||
public void setRegisteredClientId(String registeredClientId) {
|
||||
this.registeredClientId = registeredClientId;
|
||||
}
|
||||
|
||||
public String getPrincipalName() {
|
||||
return principalName;
|
||||
}
|
||||
|
||||
public void setPrincipalName(String principalName) {
|
||||
this.principalName = principalName;
|
||||
}
|
||||
|
||||
public String getAuthorities() {
|
||||
return authorities;
|
||||
}
|
||||
|
||||
public void setAuthorities(String authorities) {
|
||||
this.authorities = authorities;
|
||||
}
|
||||
// tag::class[]
|
||||
|
||||
public static class AuthorizationConsentId implements Serializable {
|
||||
private String registeredClientId;
|
||||
private String principalName;
|
||||
|
||||
// getters and setters
|
||||
// end::class[]
|
||||
public String getRegisteredClientId() {
|
||||
return registeredClientId;
|
||||
}
|
||||
|
||||
public void setRegisteredClientId(String registeredClientId) {
|
||||
this.registeredClientId = registeredClientId;
|
||||
}
|
||||
|
||||
public String getPrincipalName() {
|
||||
return principalName;
|
||||
}
|
||||
|
||||
public void setPrincipalName(String principalName) {
|
||||
this.principalName = principalName;
|
||||
}
|
||||
// tag::class[]
|
||||
|
||||
// equals and hashCode
|
||||
// end::class[]
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
AuthorizationConsentId that = (AuthorizationConsentId) o;
|
||||
return registeredClientId.equals(that.registeredClientId) && principalName.equals(that.principalName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(registeredClientId, principalName);
|
||||
}
|
||||
// tag::class[]
|
||||
}
|
||||
}
|
||||
// end::class[]
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
package sample.jpa;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
// tag::class[]
|
||||
@Repository
|
||||
public interface AuthorizationConsentRepository extends JpaRepository<AuthorizationConsent, AuthorizationConsent.AuthorizationConsentId> {
|
||||
Optional<AuthorizationConsent> findByRegisteredClientIdAndPrincipalName(String registeredClientId, String principalName);
|
||||
void deleteByRegisteredClientIdAndPrincipalName(String registeredClientId, String principalName);
|
||||
}
|
||||
// end::class[]
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
package sample.jpa;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
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<Authorization, String> {
|
||||
Optional<Authorization> findByState(String state);
|
||||
Optional<Authorization> findByAuthorizationCodeValue(String authorizationCode);
|
||||
Optional<Authorization> findByAccessTokenValue(String accessToken);
|
||||
Optional<Authorization> findByRefreshTokenValue(String refreshToken);
|
||||
@Query("select a from Authorization a where a.state = :token" +
|
||||
" or a.authorizationCodeValue = :token" +
|
||||
" or a.accessTokenValue = :token" +
|
||||
" or a.refreshTokenValue = :token"
|
||||
)
|
||||
Optional<Authorization> findByStateOrAuthorizationCodeValueOrAccessTokenValueOrRefreshTokenValue(@Param("token") String token);
|
||||
}
|
||||
// end::class[]
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
package sample.jpa;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
// tag::class[]
|
||||
@Entity
|
||||
public class Client {
|
||||
@Id
|
||||
private String id;
|
||||
private String clientId;
|
||||
private Instant clientIdIssuedAt;
|
||||
private String clientSecret;
|
||||
private Instant clientSecretExpiresAt;
|
||||
private String clientName;
|
||||
@Column(length = 1000)
|
||||
private String clientAuthenticationMethods;
|
||||
@Column(length = 1000)
|
||||
private String authorizationGrantTypes;
|
||||
@Column(length = 1000)
|
||||
private String redirectUris;
|
||||
@Column(length = 1000)
|
||||
private String scopes;
|
||||
@Column(length = 2000)
|
||||
private String clientSettings;
|
||||
@Column(length = 2000)
|
||||
private String tokenSettings;
|
||||
|
||||
// getters and setters
|
||||
// end::class[]
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public Instant getClientIdIssuedAt() {
|
||||
return clientIdIssuedAt;
|
||||
}
|
||||
|
||||
public void setClientIdIssuedAt(Instant clientIdIssuedAt) {
|
||||
this.clientIdIssuedAt = clientIdIssuedAt;
|
||||
}
|
||||
|
||||
public String getClientSecret() {
|
||||
return clientSecret;
|
||||
}
|
||||
|
||||
public void setClientSecret(String clientSecret) {
|
||||
this.clientSecret = clientSecret;
|
||||
}
|
||||
|
||||
public Instant getClientSecretExpiresAt() {
|
||||
return clientSecretExpiresAt;
|
||||
}
|
||||
|
||||
public void setClientSecretExpiresAt(Instant clientSecretExpiresAt) {
|
||||
this.clientSecretExpiresAt = clientSecretExpiresAt;
|
||||
}
|
||||
|
||||
public String getClientName() {
|
||||
return clientName;
|
||||
}
|
||||
|
||||
public void setClientName(String clientName) {
|
||||
this.clientName = clientName;
|
||||
}
|
||||
|
||||
public String getClientAuthenticationMethods() {
|
||||
return clientAuthenticationMethods;
|
||||
}
|
||||
|
||||
public void setClientAuthenticationMethods(String clientAuthenticationMethods) {
|
||||
this.clientAuthenticationMethods = clientAuthenticationMethods;
|
||||
}
|
||||
|
||||
public String getAuthorizationGrantTypes() {
|
||||
return authorizationGrantTypes;
|
||||
}
|
||||
|
||||
public void setAuthorizationGrantTypes(String authorizationGrantTypes) {
|
||||
this.authorizationGrantTypes = authorizationGrantTypes;
|
||||
}
|
||||
|
||||
public String getRedirectUris() {
|
||||
return redirectUris;
|
||||
}
|
||||
|
||||
public void setRedirectUris(String redirectUris) {
|
||||
this.redirectUris = redirectUris;
|
||||
}
|
||||
|
||||
public String getScopes() {
|
||||
return scopes;
|
||||
}
|
||||
|
||||
public void setScopes(String scopes) {
|
||||
this.scopes = scopes;
|
||||
}
|
||||
|
||||
public String getClientSettings() {
|
||||
return clientSettings;
|
||||
}
|
||||
|
||||
public void setClientSettings(String clientSettings) {
|
||||
this.clientSettings = clientSettings;
|
||||
}
|
||||
|
||||
public String getTokenSettings() {
|
||||
return tokenSettings;
|
||||
}
|
||||
|
||||
public void setTokenSettings(String tokenSettings) {
|
||||
this.tokenSettings = tokenSettings;
|
||||
}
|
||||
// tag::class[]
|
||||
}
|
||||
// end::class[]
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
package sample.jpa;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
// tag::class[]
|
||||
@Repository
|
||||
public interface ClientRepository extends JpaRepository<Client, String> {
|
||||
Optional<Client> findByClientId(String clientId);
|
||||
}
|
||||
// end::class[]
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
package sample.jpa;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||
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;
|
||||
private final RegisteredClientRepository registeredClientRepository;
|
||||
|
||||
public JpaOAuth2AuthorizationConsentService(AuthorizationConsentRepository authorizationConsentRepository, RegisteredClientRepository registeredClientRepository) {
|
||||
Assert.notNull(authorizationConsentRepository, "authorizationConsentRepository cannot be null");
|
||||
Assert.notNull(registeredClientRepository, "registeredClientRepository cannot be null");
|
||||
this.authorizationConsentRepository = authorizationConsentRepository;
|
||||
this.registeredClientRepository = registeredClientRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(OAuth2AuthorizationConsent authorizationConsent) {
|
||||
Assert.notNull(authorizationConsent, "authorizationConsent cannot be null");
|
||||
this.authorizationConsentRepository.save(toEntity(authorizationConsent));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(OAuth2AuthorizationConsent authorizationConsent) {
|
||||
Assert.notNull(authorizationConsent, "authorizationConsent cannot be null");
|
||||
this.authorizationConsentRepository.deleteByRegisteredClientIdAndPrincipalName(
|
||||
authorizationConsent.getRegisteredClientId(), authorizationConsent.getPrincipalName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AuthorizationConsent findById(String registeredClientId, String principalName) {
|
||||
Assert.hasText(registeredClientId, "registeredClientId cannot be empty");
|
||||
Assert.hasText(principalName, "principalName cannot be empty");
|
||||
return this.authorizationConsentRepository.findByRegisteredClientIdAndPrincipalName(
|
||||
registeredClientId, principalName).map(this::toObject).orElse(null);
|
||||
}
|
||||
|
||||
private OAuth2AuthorizationConsent toObject(AuthorizationConsent authorizationConsent) {
|
||||
String registeredClientId = authorizationConsent.getRegisteredClientId();
|
||||
RegisteredClient registeredClient = this.registeredClientRepository.findById(registeredClientId);
|
||||
if (registeredClient == null) {
|
||||
throw new DataRetrievalFailureException(
|
||||
"The RegisteredClient with id '" + registeredClientId + "' was not found in the RegisteredClientRepository.");
|
||||
}
|
||||
|
||||
OAuth2AuthorizationConsent.Builder builder = OAuth2AuthorizationConsent.withId(
|
||||
registeredClientId, authorizationConsent.getPrincipalName());
|
||||
if (authorizationConsent.getAuthorities() != null) {
|
||||
for (String authority : StringUtils.commaDelimitedListToSet(authorizationConsent.getAuthorities())) {
|
||||
builder.authority(new SimpleGrantedAuthority(authority));
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private AuthorizationConsent toEntity(OAuth2AuthorizationConsent authorizationConsent) {
|
||||
AuthorizationConsent entity = new AuthorizationConsent();
|
||||
entity.setRegisteredClientId(authorizationConsent.getRegisteredClientId());
|
||||
entity.setPrincipalName(authorizationConsent.getPrincipalName());
|
||||
|
||||
Set<String> authorities = new HashSet<>();
|
||||
for (GrantedAuthority authority : authorizationConsent.getAuthorities()) {
|
||||
authorities.add(authority.getAuthority());
|
||||
}
|
||||
entity.setAuthorities(StringUtils.collectionToCommaDelimitedString(authorities));
|
||||
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
// end::class[]
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
package sample.jpa;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
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 org.springframework.dao.DataRetrievalFailureException;
|
||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthorizationCode;
|
||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2Token;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenType;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||
import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module;
|
||||
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;
|
||||
private final RegisteredClientRepository registeredClientRepository;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
public JpaOAuth2AuthorizationService(AuthorizationRepository authorizationRepository, RegisteredClientRepository registeredClientRepository) {
|
||||
Assert.notNull(authorizationRepository, "authorizationRepository cannot be null");
|
||||
Assert.notNull(registeredClientRepository, "registeredClientRepository cannot be null");
|
||||
this.authorizationRepository = authorizationRepository;
|
||||
this.registeredClientRepository = registeredClientRepository;
|
||||
|
||||
ClassLoader classLoader = JpaOAuth2AuthorizationService.class.getClassLoader();
|
||||
List<Module> securityModules = SecurityJackson2Modules.getModules(classLoader);
|
||||
this.objectMapper.registerModules(securityModules);
|
||||
this.objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(OAuth2Authorization authorization) {
|
||||
Assert.notNull(authorization, "authorization cannot be null");
|
||||
this.authorizationRepository.save(toEntity(authorization));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(OAuth2Authorization authorization) {
|
||||
Assert.notNull(authorization, "authorization cannot be null");
|
||||
this.authorizationRepository.deleteById(authorization.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2Authorization findById(String id) {
|
||||
Assert.hasText(id, "id cannot be empty");
|
||||
return this.authorizationRepository.findById(id).map(this::toObject).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2Authorization findByToken(String token, OAuth2TokenType tokenType) {
|
||||
Assert.hasText(token, "token cannot be empty");
|
||||
|
||||
Optional<Authorization> result;
|
||||
if (tokenType == null) {
|
||||
result = this.authorizationRepository.findByStateOrAuthorizationCodeValueOrAccessTokenValueOrRefreshTokenValue(token);
|
||||
} else if (OAuth2ParameterNames.STATE.equals(tokenType.getValue())) {
|
||||
result = this.authorizationRepository.findByState(token);
|
||||
} else if (OAuth2ParameterNames.CODE.equals(tokenType.getValue())) {
|
||||
result = this.authorizationRepository.findByAuthorizationCodeValue(token);
|
||||
} else if (OAuth2ParameterNames.ACCESS_TOKEN.equals(tokenType.getValue())) {
|
||||
result = this.authorizationRepository.findByAccessTokenValue(token);
|
||||
} else if (OAuth2ParameterNames.REFRESH_TOKEN.equals(tokenType.getValue())) {
|
||||
result = this.authorizationRepository.findByRefreshTokenValue(token);
|
||||
} else {
|
||||
result = Optional.empty();
|
||||
}
|
||||
|
||||
return result.map(this::toObject).orElse(null);
|
||||
}
|
||||
|
||||
private OAuth2Authorization toObject(Authorization entity) {
|
||||
RegisteredClient registeredClient = this.registeredClientRepository.findById(entity.getRegisteredClientId());
|
||||
if (registeredClient == null) {
|
||||
throw new DataRetrievalFailureException(
|
||||
"The RegisteredClient with id '" + entity.getRegisteredClientId() + "' was not found in the RegisteredClientRepository.");
|
||||
}
|
||||
|
||||
OAuth2Authorization.Builder builder = OAuth2Authorization.withRegisteredClient(registeredClient)
|
||||
.id(entity.getId())
|
||||
.principalName(entity.getPrincipalName())
|
||||
.authorizationGrantType(resolveAuthorizationGrantType(entity.getAuthorizationGrantType()))
|
||||
.attributes(attributes -> attributes.putAll(parseMap(entity.getAttributes())));
|
||||
if (entity.getState() != null) {
|
||||
builder.attribute(OAuth2ParameterNames.STATE, entity.getState());
|
||||
}
|
||||
|
||||
if (entity.getAuthorizationCodeValue() != null) {
|
||||
OAuth2AuthorizationCode authorizationCode = new OAuth2AuthorizationCode(
|
||||
entity.getAuthorizationCodeValue(),
|
||||
entity.getAuthorizationCodeIssuedAt(),
|
||||
entity.getAuthorizationCodeExpiresAt());
|
||||
builder.token(authorizationCode, metadata -> metadata.putAll(parseMap(entity.getAuthorizationCodeMetadata())));
|
||||
}
|
||||
|
||||
if (entity.getAccessTokenValue() != null) {
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(
|
||||
OAuth2AccessToken.TokenType.BEARER,
|
||||
entity.getAccessTokenValue(),
|
||||
entity.getAccessTokenIssuedAt(),
|
||||
entity.getAccessTokenExpiresAt());
|
||||
builder.token(accessToken, metadata -> metadata.putAll(parseMap(entity.getAccessTokenMetadata())));
|
||||
}
|
||||
|
||||
if (entity.getRefreshTokenValue() != null) {
|
||||
OAuth2RefreshToken refreshToken = new OAuth2RefreshToken(
|
||||
entity.getRefreshTokenValue(),
|
||||
entity.getRefreshTokenIssuedAt(),
|
||||
entity.getRefreshTokenExpiresAt());
|
||||
builder.token(refreshToken, metadata -> metadata.putAll(parseMap(entity.getRefreshTokenMetadata())));
|
||||
}
|
||||
|
||||
if (entity.getOidcIdTokenValue() != null) {
|
||||
OidcIdToken idToken = new OidcIdToken(
|
||||
entity.getOidcIdTokenValue(),
|
||||
entity.getOidcIdTokenIssuedAt(),
|
||||
entity.getOidcIdTokenExpiresAt(),
|
||||
parseMap(entity.getOidcIdTokenClaims()));
|
||||
builder.token(idToken, metadata -> metadata.putAll(parseMap(entity.getOidcIdTokenMetadata())));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private Authorization toEntity(OAuth2Authorization authorization) {
|
||||
Authorization entity = new Authorization();
|
||||
entity.setId(authorization.getId());
|
||||
entity.setRegisteredClientId(authorization.getRegisteredClientId());
|
||||
entity.setPrincipalName(authorization.getPrincipalName());
|
||||
entity.setAuthorizationGrantType(authorization.getAuthorizationGrantType().getValue());
|
||||
entity.setAttributes(writeMap(authorization.getAttributes()));
|
||||
entity.setState(authorization.getAttribute(OAuth2ParameterNames.STATE));
|
||||
|
||||
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode =
|
||||
authorization.getToken(OAuth2AuthorizationCode.class);
|
||||
setTokenValues(
|
||||
authorizationCode,
|
||||
entity::setAuthorizationCodeValue,
|
||||
entity::setAuthorizationCodeIssuedAt,
|
||||
entity::setAuthorizationCodeExpiresAt,
|
||||
entity::setAuthorizationCodeMetadata
|
||||
);
|
||||
|
||||
OAuth2Authorization.Token<OAuth2AccessToken> accessToken =
|
||||
authorization.getToken(OAuth2AccessToken.class);
|
||||
setTokenValues(
|
||||
accessToken,
|
||||
entity::setAccessTokenValue,
|
||||
entity::setAccessTokenIssuedAt,
|
||||
entity::setAccessTokenExpiresAt,
|
||||
entity::setAccessTokenMetadata
|
||||
);
|
||||
if (accessToken != null && accessToken.getToken().getScopes() != null) {
|
||||
entity.setAccessTokenScopes(StringUtils.collectionToDelimitedString(accessToken.getToken().getScopes(), ","));
|
||||
}
|
||||
|
||||
OAuth2Authorization.Token<OAuth2RefreshToken> refreshToken =
|
||||
authorization.getToken(OAuth2RefreshToken.class);
|
||||
setTokenValues(
|
||||
refreshToken,
|
||||
entity::setRefreshTokenValue,
|
||||
entity::setRefreshTokenIssuedAt,
|
||||
entity::setRefreshTokenExpiresAt,
|
||||
entity::setRefreshTokenMetadata
|
||||
);
|
||||
|
||||
OAuth2Authorization.Token<OidcIdToken> oidcIdToken =
|
||||
authorization.getToken(OidcIdToken.class);
|
||||
setTokenValues(
|
||||
oidcIdToken,
|
||||
entity::setOidcIdTokenValue,
|
||||
entity::setOidcIdTokenIssuedAt,
|
||||
entity::setOidcIdTokenExpiresAt,
|
||||
entity::setOidcIdTokenMetadata
|
||||
);
|
||||
if (oidcIdToken != null) {
|
||||
entity.setOidcIdTokenClaims(writeMap(oidcIdToken.getClaims()));
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
private void setTokenValues(
|
||||
OAuth2Authorization.Token<?> token,
|
||||
Consumer<String> tokenValueConsumer,
|
||||
Consumer<Instant> issuedAtConsumer,
|
||||
Consumer<Instant> expiresAtConsumer,
|
||||
Consumer<String> metadataConsumer) {
|
||||
if (token != null) {
|
||||
OAuth2Token oAuth2Token = token.getToken();
|
||||
tokenValueConsumer.accept(oAuth2Token.getTokenValue());
|
||||
issuedAtConsumer.accept(oAuth2Token.getIssuedAt());
|
||||
expiresAtConsumer.accept(oAuth2Token.getExpiresAt());
|
||||
metadataConsumer.accept(writeMap(token.getMetadata()));
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> parseMap(String data) {
|
||||
try {
|
||||
return this.objectMapper.readValue(data, new TypeReference<>() {
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalArgumentException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private String writeMap(Map<String, Object> metadata) {
|
||||
try {
|
||||
return this.objectMapper.writeValueAsString(metadata);
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalArgumentException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static AuthorizationGrantType resolveAuthorizationGrantType(String authorizationGrantType) {
|
||||
if (AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equals(authorizationGrantType)) {
|
||||
return AuthorizationGrantType.AUTHORIZATION_CODE;
|
||||
} else if (AuthorizationGrantType.CLIENT_CREDENTIALS.getValue().equals(authorizationGrantType)) {
|
||||
return AuthorizationGrantType.CLIENT_CREDENTIALS;
|
||||
} else if (AuthorizationGrantType.REFRESH_TOKEN.getValue().equals(authorizationGrantType)) {
|
||||
return AuthorizationGrantType.REFRESH_TOKEN;
|
||||
}
|
||||
return new AuthorizationGrantType(authorizationGrantType); // Custom authorization grant type
|
||||
}
|
||||
}
|
||||
// end::class[]
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
package sample.jpa;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||
import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
|
||||
import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
|
||||
import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module;
|
||||
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;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
public JpaRegisteredClientRepository(ClientRepository clientRepository) {
|
||||
Assert.notNull(clientRepository, "clientRepository cannot be null");
|
||||
this.clientRepository = clientRepository;
|
||||
|
||||
ClassLoader classLoader = JpaRegisteredClientRepository.class.getClassLoader();
|
||||
List<Module> securityModules = SecurityJackson2Modules.getModules(classLoader);
|
||||
this.objectMapper.registerModules(securityModules);
|
||||
this.objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(RegisteredClient registeredClient) {
|
||||
Assert.notNull(registeredClient, "registeredClient cannot be null");
|
||||
this.clientRepository.save(toEntity(registeredClient));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisteredClient findById(String id) {
|
||||
Assert.hasText(id, "id cannot be empty");
|
||||
return this.clientRepository.findById(id).map(this::toObject).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisteredClient findByClientId(String clientId) {
|
||||
Assert.hasText(clientId, "clientId cannot be empty");
|
||||
return this.clientRepository.findByClientId(clientId).map(this::toObject).orElse(null);
|
||||
}
|
||||
|
||||
private RegisteredClient toObject(Client client) {
|
||||
Set<String> clientAuthenticationMethods = StringUtils.commaDelimitedListToSet(
|
||||
client.getClientAuthenticationMethods());
|
||||
Set<String> authorizationGrantTypes = StringUtils.commaDelimitedListToSet(
|
||||
client.getAuthorizationGrantTypes());
|
||||
Set<String> redirectUris = StringUtils.commaDelimitedListToSet(
|
||||
client.getRedirectUris());
|
||||
Set<String> clientScopes = StringUtils.commaDelimitedListToSet(
|
||||
client.getScopes());
|
||||
|
||||
RegisteredClient.Builder builder = RegisteredClient.withId(client.getId())
|
||||
.clientId(client.getClientId())
|
||||
.clientIdIssuedAt(client.getClientIdIssuedAt())
|
||||
.clientSecret(client.getClientSecret())
|
||||
.clientSecretExpiresAt(client.getClientSecretExpiresAt())
|
||||
.clientName(client.getClientName())
|
||||
.clientAuthenticationMethods(authenticationMethods ->
|
||||
clientAuthenticationMethods.forEach(authenticationMethod ->
|
||||
authenticationMethods.add(resolveClientAuthenticationMethod(authenticationMethod))))
|
||||
.authorizationGrantTypes((grantTypes) ->
|
||||
authorizationGrantTypes.forEach(grantType ->
|
||||
grantTypes.add(resolveAuthorizationGrantType(grantType))))
|
||||
.redirectUris((uris) -> uris.addAll(redirectUris))
|
||||
.scopes((scopes) -> scopes.addAll(clientScopes));
|
||||
|
||||
Map<String, Object> clientSettingsMap = parseMap(client.getClientSettings());
|
||||
builder.clientSettings(ClientSettings.withSettings(clientSettingsMap).build());
|
||||
|
||||
Map<String, Object> tokenSettingsMap = parseMap(client.getTokenSettings());
|
||||
builder.tokenSettings(TokenSettings.withSettings(tokenSettingsMap).build());
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private Client toEntity(RegisteredClient registeredClient) {
|
||||
List<String> clientAuthenticationMethods = new ArrayList<>(registeredClient.getClientAuthenticationMethods().size());
|
||||
registeredClient.getClientAuthenticationMethods().forEach(clientAuthenticationMethod ->
|
||||
clientAuthenticationMethods.add(clientAuthenticationMethod.getValue()));
|
||||
|
||||
List<String> authorizationGrantTypes = new ArrayList<>(registeredClient.getAuthorizationGrantTypes().size());
|
||||
registeredClient.getAuthorizationGrantTypes().forEach(authorizationGrantType ->
|
||||
authorizationGrantTypes.add(authorizationGrantType.getValue()));
|
||||
|
||||
Client entity = new Client();
|
||||
entity.setId(registeredClient.getId());
|
||||
entity.setClientId(registeredClient.getClientId());
|
||||
entity.setClientIdIssuedAt(registeredClient.getClientIdIssuedAt());
|
||||
entity.setClientSecret(registeredClient.getClientSecret());
|
||||
entity.setClientSecretExpiresAt(registeredClient.getClientSecretExpiresAt());
|
||||
entity.setClientName(registeredClient.getClientName());
|
||||
entity.setClientAuthenticationMethods(StringUtils.collectionToCommaDelimitedString(clientAuthenticationMethods));
|
||||
entity.setAuthorizationGrantTypes(StringUtils.collectionToCommaDelimitedString(authorizationGrantTypes));
|
||||
entity.setRedirectUris(StringUtils.collectionToCommaDelimitedString(registeredClient.getRedirectUris()));
|
||||
entity.setScopes(StringUtils.collectionToCommaDelimitedString(registeredClient.getScopes()));
|
||||
entity.setClientSettings(writeMap(registeredClient.getClientSettings().getSettings()));
|
||||
entity.setTokenSettings(writeMap(registeredClient.getTokenSettings().getSettings()));
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
private Map<String, Object> parseMap(String data) {
|
||||
try {
|
||||
return this.objectMapper.readValue(data, new TypeReference<>() {
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalArgumentException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private String writeMap(Map<String, Object> data) {
|
||||
try {
|
||||
return this.objectMapper.writeValueAsString(data);
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalArgumentException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static AuthorizationGrantType resolveAuthorizationGrantType(String authorizationGrantType) {
|
||||
if (AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equals(authorizationGrantType)) {
|
||||
return AuthorizationGrantType.AUTHORIZATION_CODE;
|
||||
} else if (AuthorizationGrantType.CLIENT_CREDENTIALS.getValue().equals(authorizationGrantType)) {
|
||||
return AuthorizationGrantType.CLIENT_CREDENTIALS;
|
||||
} else if (AuthorizationGrantType.REFRESH_TOKEN.getValue().equals(authorizationGrantType)) {
|
||||
return AuthorizationGrantType.REFRESH_TOKEN;
|
||||
}
|
||||
return new AuthorizationGrantType(authorizationGrantType); // Custom authorization grant type
|
||||
}
|
||||
|
||||
private static ClientAuthenticationMethod resolveClientAuthenticationMethod(String clientAuthenticationMethod) {
|
||||
if (ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue().equals(clientAuthenticationMethod)) {
|
||||
return ClientAuthenticationMethod.CLIENT_SECRET_BASIC;
|
||||
} else if (ClientAuthenticationMethod.CLIENT_SECRET_POST.getValue().equals(clientAuthenticationMethod)) {
|
||||
return ClientAuthenticationMethod.CLIENT_SECRET_POST;
|
||||
} else if (ClientAuthenticationMethod.NONE.getValue().equals(clientAuthenticationMethod)) {
|
||||
return ClientAuthenticationMethod.NONE;
|
||||
}
|
||||
return new ClientAuthenticationMethod(clientAuthenticationMethod); // Custom client authentication method
|
||||
}
|
||||
}
|
||||
// end::class[]
|
||||
@@ -0,0 +1,6 @@
|
||||
server:
|
||||
port: 9000
|
||||
|
||||
logging:
|
||||
level:
|
||||
org.springframework.security: trace
|
||||
@@ -0,0 +1,6 @@
|
||||
CREATE TABLE authorizationConsent (
|
||||
registeredClientId varchar(255) NOT NULL,
|
||||
principalName varchar(255) NOT NULL,
|
||||
authorities varchar(1000) NOT NULL,
|
||||
PRIMARY KEY (registeredClientId, principalName)
|
||||
);
|
||||
@@ -0,0 +1,28 @@
|
||||
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)
|
||||
);
|
||||
@@ -0,0 +1,15 @@
|
||||
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)
|
||||
);
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2020-2021 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.
|
||||
*/
|
||||
package sample.jose;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import com.nimbusds.jose.jwk.Curve;
|
||||
import com.nimbusds.jose.jwk.ECKey;
|
||||
import com.nimbusds.jose.jwk.KeyUse;
|
||||
import com.nimbusds.jose.jwk.OctetSequenceKey;
|
||||
import com.nimbusds.jose.jwk.RSAKey;
|
||||
|
||||
/**
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
public final class TestJwks {
|
||||
|
||||
private static final KeyPairGenerator rsaKeyPairGenerator;
|
||||
static {
|
||||
try {
|
||||
rsaKeyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||
rsaKeyPairGenerator.initialize(2048);
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// @formatter:off
|
||||
public static final RSAKey DEFAULT_RSA_JWK =
|
||||
jwk(
|
||||
TestKeys.DEFAULT_PUBLIC_KEY,
|
||||
TestKeys.DEFAULT_PRIVATE_KEY
|
||||
).build();
|
||||
// @formatter:on
|
||||
|
||||
// @formatter:off
|
||||
public static final ECKey DEFAULT_EC_JWK =
|
||||
jwk(
|
||||
(ECPublicKey) TestKeys.DEFAULT_EC_KEY_PAIR.getPublic(),
|
||||
(ECPrivateKey) TestKeys.DEFAULT_EC_KEY_PAIR.getPrivate()
|
||||
).build();
|
||||
// @formatter:on
|
||||
|
||||
// @formatter:off
|
||||
public static final OctetSequenceKey DEFAULT_SECRET_JWK =
|
||||
jwk(
|
||||
TestKeys.DEFAULT_SECRET_KEY
|
||||
).build();
|
||||
// @formatter:on
|
||||
|
||||
private TestJwks() {
|
||||
}
|
||||
|
||||
public static RSAKey.Builder generateRsaJwk() {
|
||||
KeyPair keyPair = rsaKeyPairGenerator.generateKeyPair();
|
||||
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
|
||||
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
|
||||
// @formatter:off
|
||||
return jwk(publicKey, privateKey)
|
||||
.keyID(UUID.randomUUID().toString());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
public static RSAKey.Builder jwk(RSAPublicKey publicKey, RSAPrivateKey privateKey) {
|
||||
// @formatter:off
|
||||
return new RSAKey.Builder(publicKey)
|
||||
.privateKey(privateKey)
|
||||
.keyUse(KeyUse.SIGNATURE)
|
||||
.keyID("rsa-jwk-kid");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
public static ECKey.Builder jwk(ECPublicKey publicKey, ECPrivateKey privateKey) {
|
||||
// @formatter:off
|
||||
Curve curve = Curve.forECParameterSpec(publicKey.getParams());
|
||||
return new ECKey.Builder(curve, publicKey)
|
||||
.privateKey(privateKey)
|
||||
.keyUse(KeyUse.SIGNATURE)
|
||||
.keyID("ec-jwk-kid");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
public static OctetSequenceKey.Builder jwk(SecretKey secretKey) {
|
||||
// @formatter:off
|
||||
return new OctetSequenceKey.Builder(secretKey)
|
||||
.keyUse(KeyUse.SIGNATURE)
|
||||
.keyID("secret-jwk-kid");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
*/
|
||||
|
||||
package sample.jose;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.ECFieldFp;
|
||||
import java.security.spec.ECParameterSpec;
|
||||
import java.security.spec.ECPoint;
|
||||
import java.security.spec.EllipticCurve;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* This class is a straight copy from Spring Security.
|
||||
* It should be removed when merging this codebase into Spring Security.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @since 5.2
|
||||
*/
|
||||
public final class TestKeys {
|
||||
|
||||
public static final KeyFactory kf;
|
||||
static {
|
||||
try {
|
||||
kf = KeyFactory.getInstance("RSA");
|
||||
}
|
||||
catch (NoSuchAlgorithmException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
public static final String DEFAULT_ENCODED_SECRET_KEY = "bCzY/M48bbkwBEWjmNSIEPfwApcvXOnkCxORBEbPr+4=";
|
||||
|
||||
public static final SecretKey DEFAULT_SECRET_KEY = new SecretKeySpec(
|
||||
Base64.getDecoder().decode(DEFAULT_ENCODED_SECRET_KEY), "AES");
|
||||
|
||||
// @formatter:off
|
||||
public static final String DEFAULT_RSA_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3FlqJr5TRskIQIgdE3Dd"
|
||||
+ "7D9lboWdcTUT8a+fJR7MAvQm7XXNoYkm3v7MQL1NYtDvL2l8CAnc0WdSTINU6IRv"
|
||||
+ "c5Kqo2Q4csNX9SHOmEfzoROjQqahEcve1jBXluoCXdYuYpx4/1tfRgG6ii4Uhxh6"
|
||||
+ "iI8qNMJQX+fLfqhbfYfxBQVRPywBkAbIP4x1EAsbC6FSNmkhCxiMNqEgxaIpY8C2"
|
||||
+ "kJdJ/ZIV+WW4noDdzpKqHcwmB8FsrumlVY/DNVvUSDIipiq9PbP4H99TXN1o746o"
|
||||
+ "RaNa07rq1hoCgMSSy+85SagCoxlmyE+D+of9SsMY8Ol9t0rdzpobBuhyJ/o5dfvj"
|
||||
+ "KwIDAQAB";
|
||||
// @formatter:on
|
||||
|
||||
public static final RSAPublicKey DEFAULT_PUBLIC_KEY;
|
||||
static {
|
||||
X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.getDecoder().decode(DEFAULT_RSA_PUBLIC_KEY));
|
||||
try {
|
||||
DEFAULT_PUBLIC_KEY = (RSAPublicKey) kf.generatePublic(spec);
|
||||
}
|
||||
catch (InvalidKeySpecException ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// @formatter:off
|
||||
public static final String DEFAULT_RSA_PRIVATE_KEY = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDcWWomvlNGyQhA"
|
||||
+ "iB0TcN3sP2VuhZ1xNRPxr58lHswC9Cbtdc2hiSbe/sxAvU1i0O8vaXwICdzRZ1JM"
|
||||
+ "g1TohG9zkqqjZDhyw1f1Ic6YR/OhE6NCpqERy97WMFeW6gJd1i5inHj/W19GAbqK"
|
||||
+ "LhSHGHqIjyo0wlBf58t+qFt9h/EFBVE/LAGQBsg/jHUQCxsLoVI2aSELGIw2oSDF"
|
||||
+ "oiljwLaQl0n9khX5ZbiegN3OkqodzCYHwWyu6aVVj8M1W9RIMiKmKr09s/gf31Nc"
|
||||
+ "3WjvjqhFo1rTuurWGgKAxJLL7zlJqAKjGWbIT4P6h/1Kwxjw6X23St3OmhsG6HIn"
|
||||
+ "+jl1++MrAgMBAAECggEBAMf820wop3pyUOwI3aLcaH7YFx5VZMzvqJdNlvpg1jbE"
|
||||
+ "E2Sn66b1zPLNfOIxLcBG8x8r9Ody1Bi2Vsqc0/5o3KKfdgHvnxAB3Z3dPh2WCDek"
|
||||
+ "lCOVClEVoLzziTuuTdGO5/CWJXdWHcVzIjPxmK34eJXioiLaTYqN3XKqKMdpD0ZG"
|
||||
+ "mtNTGvGf+9fQ4i94t0WqIxpMpGt7NM4RHy3+Onggev0zLiDANC23mWrTsUgect/7"
|
||||
+ "62TYg8g1bKwLAb9wCBT+BiOuCc2wrArRLOJgUkj/F4/gtrR9ima34SvWUyoUaKA0"
|
||||
+ "bi4YBX9l8oJwFGHbU9uFGEMnH0T/V0KtIB7qetReywkCgYEA9cFyfBIQrYISV/OA"
|
||||
+ "+Z0bo3vh2aL0QgKrSXZ924cLt7itQAHNZ2ya+e3JRlTczi5mnWfjPWZ6eJB/8MlH"
|
||||
+ "Gpn12o/POEkU+XjZZSPe1RWGt5g0S3lWqyx9toCS9ACXcN9tGbaqcFSVI73zVTRA"
|
||||
+ "8J9grR0fbGn7jaTlTX2tnlOTQ60CgYEA5YjYpEq4L8UUMFkuj+BsS3u0oEBnzuHd"
|
||||
+ "I9LEHmN+CMPosvabQu5wkJXLuqo2TxRnAznsA8R3pCLkdPGoWMCiWRAsCn979TdY"
|
||||
+ "QbqO2qvBAD2Q19GtY7lIu6C35/enQWzJUMQE3WW0OvjLzZ0l/9mA2FBRR+3F9A1d"
|
||||
+ "rBdnmv0c3TcCgYEAi2i+ggVZcqPbtgrLOk5WVGo9F1GqUBvlgNn30WWNTx4zIaEk"
|
||||
+ "HSxtyaOLTxtq2odV7Kr3LGiKxwPpn/T+Ief+oIp92YcTn+VfJVGw4Z3BezqbR8lA"
|
||||
+ "Uf/+HF5ZfpMrVXtZD4Igs3I33Duv4sCuqhEvLWTc44pHifVloozNxYfRfU0CgYBN"
|
||||
+ "HXa7a6cJ1Yp829l62QlJKtx6Ymj95oAnQu5Ez2ROiZMqXRO4nucOjGUP55Orac1a"
|
||||
+ "FiGm+mC/skFS0MWgW8evaHGDbWU180wheQ35hW6oKAb7myRHtr4q20ouEtQMdQIF"
|
||||
+ "snV39G1iyqeeAsf7dxWElydXpRi2b68i3BIgzhzebQKBgQCdUQuTsqV9y/JFpu6H"
|
||||
+ "c5TVvhG/ubfBspI5DhQqIGijnVBzFT//UfIYMSKJo75qqBEyP2EJSmCsunWsAFsM"
|
||||
+ "TszuiGTkrKcZy9G0wJqPztZZl2F2+bJgnA6nBEV7g5PA4Af+QSmaIhRwqGDAuROR"
|
||||
+ "47jndeyIaMTNETEmOnms+as17g==";
|
||||
// @formatter:on
|
||||
|
||||
public static final RSAPrivateKey DEFAULT_PRIVATE_KEY;
|
||||
static {
|
||||
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(DEFAULT_RSA_PRIVATE_KEY));
|
||||
try {
|
||||
DEFAULT_PRIVATE_KEY = (RSAPrivateKey) kf.generatePrivate(spec);
|
||||
}
|
||||
catch (InvalidKeySpecException ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static final KeyPair DEFAULT_RSA_KEY_PAIR = new KeyPair(DEFAULT_PUBLIC_KEY, DEFAULT_PRIVATE_KEY);
|
||||
|
||||
public static final KeyPair DEFAULT_EC_KEY_PAIR = generateEcKeyPair();
|
||||
|
||||
static KeyPair generateEcKeyPair() {
|
||||
EllipticCurve ellipticCurve = new EllipticCurve(
|
||||
new ECFieldFp(new BigInteger(
|
||||
"115792089210356248762697446949407573530086143415290314195533631308867097853951")),
|
||||
new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853948"),
|
||||
new BigInteger("41058363725152142129326129780047268409114441015993725554835256314039467401291"));
|
||||
ECPoint ecPoint = new ECPoint(
|
||||
new BigInteger("48439561293906451759052585252797914202762949526041747995844080717082404635286"),
|
||||
new BigInteger("36134250956749795798585127919587881956611106672985015071877198253568414405109"));
|
||||
ECParameterSpec ecParameterSpec = new ECParameterSpec(ellipticCurve, ecPoint,
|
||||
new BigInteger("115792089210356248762697446949407573529996955224135760342422259061068512044369"), 1);
|
||||
|
||||
KeyPair keyPair;
|
||||
try {
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
|
||||
keyPairGenerator.initialize(ecParameterSpec);
|
||||
keyPair = keyPairGenerator.generateKeyPair();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
private TestKeys() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package sample.jpa;
|
||||
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.nimbusds.jose.jwk.JWKSet;
|
||||
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
|
||||
import com.nimbusds.jose.jwk.source.JWKSource;
|
||||
import com.nimbusds.jose.proc.SecurityContext;
|
||||
import org.assertj.core.api.ObjectAssert;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import sample.jose.TestJwks;
|
||||
import sample.test.SpringTestContext;
|
||||
import sample.test.SpringTestContextExtension;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenType;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.UriComponents;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import static sample.util.RegisteredClients.messagingClient;
|
||||
|
||||
/**
|
||||
* Tests for the guide How-to: Implement core services with JPA.
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class JpaTests {
|
||||
|
||||
private static final Pattern HIDDEN_STATE_INPUT_PATTERN = Pattern.compile(".+<input type=\"hidden\" name=\"state\" value=\"([^\"]+)\">.+");
|
||||
private static final TypeReference<Map<String, Object>> TOKEN_RESPONSE_TYPE_REFERENCE = new TypeReference<>() {
|
||||
};
|
||||
|
||||
public final SpringTestContext spring = new SpringTestContext(this);
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private RegisteredClientRepository registeredClientRepository;
|
||||
|
||||
@Autowired
|
||||
private OAuth2AuthorizationService authorizationService;
|
||||
|
||||
@Autowired
|
||||
private OAuth2AuthorizationConsentService authorizationConsentService;
|
||||
|
||||
@Test
|
||||
public void oidcLoginWhenJpaCoreServicesAutowiredThenUsed() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfig.class).autowire();
|
||||
assertThat(this.registeredClientRepository).isInstanceOf(JpaRegisteredClientRepository.class);
|
||||
assertThat(this.authorizationService).isInstanceOf(JpaOAuth2AuthorizationService.class);
|
||||
assertThat(this.authorizationConsentService).isInstanceOf(JpaOAuth2AuthorizationConsentService.class);
|
||||
|
||||
RegisteredClient registeredClient = messagingClient();
|
||||
this.registeredClientRepository.save(registeredClient);
|
||||
|
||||
String state = performAuthorizationCodeRequest(registeredClient);
|
||||
assertThatAuthorization(state, OAuth2ParameterNames.STATE).isNotNull();
|
||||
assertThatAuthorization(state, null).isNotNull();
|
||||
|
||||
String authorizationCode = performAuthorizationConsentRequest(registeredClient, state);
|
||||
assertThatAuthorization(authorizationCode, OAuth2ParameterNames.CODE).isNotNull();
|
||||
assertThatAuthorization(authorizationCode, null).isNotNull();
|
||||
|
||||
Map<String, Object> tokenResponse = performTokenRequest(registeredClient, authorizationCode);
|
||||
String accessToken = (String) tokenResponse.get(OAuth2ParameterNames.ACCESS_TOKEN);
|
||||
assertThatAuthorization(accessToken, OAuth2ParameterNames.ACCESS_TOKEN).isNotNull();
|
||||
assertThatAuthorization(accessToken, null).isNotNull();
|
||||
|
||||
String refreshToken = (String) tokenResponse.get(OAuth2ParameterNames.REFRESH_TOKEN);
|
||||
assertThatAuthorization(refreshToken, OAuth2ParameterNames.REFRESH_TOKEN).isNotNull();
|
||||
assertThatAuthorization(refreshToken, null).isNotNull();
|
||||
|
||||
String idToken = (String) tokenResponse.get(OidcParameterNames.ID_TOKEN);
|
||||
assertThatAuthorization(idToken, OidcParameterNames.ID_TOKEN).isNull(); // id_token is not searchable
|
||||
|
||||
OAuth2Authorization authorization = findAuthorization(accessToken, OAuth2ParameterNames.ACCESS_TOKEN);
|
||||
assertThat(authorization.getToken(idToken)).isNotNull();
|
||||
|
||||
String scopes = (String) tokenResponse.get(OAuth2ParameterNames.SCOPE);
|
||||
OAuth2AuthorizationConsent authorizationConsent = this.authorizationConsentService.findById(
|
||||
registeredClient.getId(), "user");
|
||||
assertThat(authorizationConsent).isNotNull();
|
||||
assertThat(authorizationConsent.getScopes()).containsExactlyInAnyOrder(
|
||||
StringUtils.delimitedListToStringArray(scopes, " "));
|
||||
}
|
||||
|
||||
private ObjectAssert<OAuth2Authorization> assertThatAuthorization(String token, String tokenType) {
|
||||
return assertThat(findAuthorization(token, tokenType));
|
||||
}
|
||||
|
||||
private OAuth2Authorization findAuthorization(String token, String tokenType) {
|
||||
return this.authorizationService.findByToken(token, tokenType == null ? null : new OAuth2TokenType(tokenType));
|
||||
}
|
||||
|
||||
private String performAuthorizationCodeRequest(RegisteredClient registeredClient) throws Exception {
|
||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
||||
parameters.set(OAuth2ParameterNames.RESPONSE_TYPE, OAuth2AuthorizationResponseType.CODE.getValue());
|
||||
parameters.set(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId());
|
||||
parameters.set(OAuth2ParameterNames.REDIRECT_URI, registeredClient.getRedirectUris().iterator().next());
|
||||
parameters.set(OAuth2ParameterNames.SCOPE,
|
||||
StringUtils.collectionToDelimitedString(registeredClient.getScopes(), " "));
|
||||
parameters.set(OAuth2ParameterNames.STATE, "state");
|
||||
|
||||
MvcResult mvcResult = this.mockMvc.perform(get("/oauth2/authorize")
|
||||
.params(parameters)
|
||||
.with(user("user").roles("USER")))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string("content-type", containsString(MediaType.TEXT_HTML_VALUE)))
|
||||
.andReturn();
|
||||
String responseHtml = mvcResult.getResponse().getContentAsString();
|
||||
Matcher matcher = HIDDEN_STATE_INPUT_PATTERN.matcher(responseHtml);
|
||||
|
||||
return matcher.matches() ? matcher.group(1) : null;
|
||||
}
|
||||
|
||||
private String performAuthorizationConsentRequest(RegisteredClient registeredClient, String state) throws Exception {
|
||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
||||
parameters.set(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId());
|
||||
parameters.set(OAuth2ParameterNames.STATE, state);
|
||||
parameters.add(OAuth2ParameterNames.SCOPE, "message.read");
|
||||
parameters.add(OAuth2ParameterNames.SCOPE, "message.write");
|
||||
|
||||
MvcResult mvcResult = this.mockMvc.perform(post("/oauth2/authorize")
|
||||
.params(parameters)
|
||||
.with(user("user").roles("USER")))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andReturn();
|
||||
String redirectedUrl = mvcResult.getResponse().getRedirectedUrl();
|
||||
assertThat(redirectedUrl).isNotNull();
|
||||
assertThat(redirectedUrl).matches("http://127.0.0.1:8080/authorized\\?code=.{15,}&state=state");
|
||||
|
||||
String locationHeader = URLDecoder.decode(redirectedUrl, StandardCharsets.UTF_8.name());
|
||||
UriComponents uriComponents = UriComponentsBuilder.fromUriString(locationHeader).build();
|
||||
|
||||
return uriComponents.getQueryParams().getFirst("code");
|
||||
}
|
||||
|
||||
private Map<String, Object> performTokenRequest(RegisteredClient registeredClient, String authorizationCode) throws Exception {
|
||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
||||
parameters.set(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue());
|
||||
parameters.set(OAuth2ParameterNames.CODE, authorizationCode);
|
||||
parameters.set(OAuth2ParameterNames.REDIRECT_URI, registeredClient.getRedirectUris().iterator().next());
|
||||
|
||||
HttpHeaders basicAuth = new HttpHeaders();
|
||||
basicAuth.setBasicAuth(registeredClient.getClientId(), "secret");
|
||||
|
||||
MvcResult mvcResult = this.mockMvc.perform(post("/oauth2/token")
|
||||
.params(parameters)
|
||||
.headers(basicAuth))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string(HttpHeaders.CONTENT_TYPE, containsString(MediaType.APPLICATION_JSON_VALUE)))
|
||||
.andExpect(jsonPath("$.access_token").isNotEmpty())
|
||||
.andExpect(jsonPath("$.token_type").isNotEmpty())
|
||||
.andExpect(jsonPath("$.expires_in").isNotEmpty())
|
||||
.andExpect(jsonPath("$.refresh_token").isNotEmpty())
|
||||
.andExpect(jsonPath("$.scope").isNotEmpty())
|
||||
.andExpect(jsonPath("$.id_token").isNotEmpty())
|
||||
.andReturn();
|
||||
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
String responseJson = mvcResult.getResponse().getContentAsString();
|
||||
return objectMapper.readValue(responseJson, TOKEN_RESPONSE_TYPE_REFERENCE);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan
|
||||
@Import(OAuth2AuthorizationServerConfiguration.class)
|
||||
static class AuthorizationServerConfig {
|
||||
|
||||
@Bean
|
||||
public JWKSource<SecurityContext> jwkSource() {
|
||||
JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK);
|
||||
return new ImmutableJWKSet<>(jwkSet);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
|
||||
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2002-2017 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.
|
||||
*/
|
||||
|
||||
package sample.test;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
|
||||
import org.springframework.mock.web.MockServletConfig;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.test.context.web.GenericXmlWebContextLoader;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.RequestPostProcessor;
|
||||
import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcConfigurer;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.context.support.XmlWebApplicationContext;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* This class is a straight copy from Spring Security.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class SpringTestContext implements Closeable {
|
||||
|
||||
private Object test;
|
||||
|
||||
private ConfigurableWebApplicationContext context;
|
||||
|
||||
private List<Filter> filters = new ArrayList<>();
|
||||
|
||||
public SpringTestContext(Object test) {
|
||||
setTest(test);
|
||||
}
|
||||
|
||||
public void setTest(Object test) {
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
this.context.close();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
|
||||
public SpringTestContext context(ConfigurableWebApplicationContext context) {
|
||||
this.context = context;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SpringTestContext register(Class<?>... classes) {
|
||||
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
|
||||
applicationContext.register(classes);
|
||||
this.context = applicationContext;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SpringTestContext testConfigLocations(String... configLocations) {
|
||||
GenericXmlWebContextLoader loader = new GenericXmlWebContextLoader();
|
||||
String[] locations = loader.processLocations(this.test.getClass(), configLocations);
|
||||
return configLocations(locations);
|
||||
}
|
||||
|
||||
public SpringTestContext configLocations(String... configLocations) {
|
||||
XmlWebApplicationContext context = new XmlWebApplicationContext();
|
||||
context.setConfigLocations(configLocations);
|
||||
this.context = context;
|
||||
return this;
|
||||
}
|
||||
|
||||
// public SpringTestContext context(String configuration) {
|
||||
// InMemoryXmlWebApplicationContext context = new InMemoryXmlWebApplicationContext(configuration);
|
||||
// this.context = context;
|
||||
// return this;
|
||||
// }
|
||||
|
||||
public SpringTestContext mockMvcAfterSpringSecurityOk() {
|
||||
return addFilter(new OncePerRequestFilter() {
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain filterChain) {
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private SpringTestContext addFilter(Filter filter) {
|
||||
this.filters.add(filter);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfigurableWebApplicationContext getContext() {
|
||||
if (!this.context.isRunning()) {
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.setServletConfig(new MockServletConfig());
|
||||
this.context.refresh();
|
||||
}
|
||||
return this.context;
|
||||
}
|
||||
|
||||
public void autowire() {
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.setServletConfig(new MockServletConfig());
|
||||
this.context.refresh();
|
||||
if (this.context.containsBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN)) {
|
||||
// @formatter:off
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).
|
||||
apply(springSecurity())
|
||||
.apply(new AddFilter())
|
||||
.build();
|
||||
// @formatter:on
|
||||
this.context.getBeanFactory().registerResolvableDependency(MockMvc.class, mockMvc);
|
||||
}
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(this.context.getBeanFactory());
|
||||
bpp.processInjection(this.test);
|
||||
}
|
||||
|
||||
private class AddFilter implements MockMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public RequestPostProcessor beforeMockMvcCreated(ConfigurableMockMvcBuilder<?> builder,
|
||||
WebApplicationContext context) {
|
||||
builder.addFilters(SpringTestContext.this.filters.toArray(new Filter[0]));
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2002-2017 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.
|
||||
*/
|
||||
|
||||
package sample.test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback;
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
|
||||
import org.springframework.security.test.context.TestSecurityContextHolder;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* This class is a straight copy from Spring Security.
|
||||
*/
|
||||
public class SpringTestContextExtension implements BeforeEachCallback, AfterEachCallback {
|
||||
|
||||
@Override
|
||||
public void afterEach(ExtensionContext context) throws Exception {
|
||||
TestSecurityContextHolder.clearContext();
|
||||
getContexts(context.getRequiredTestInstance()).forEach((springTestContext) -> springTestContext.close());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeEach(ExtensionContext context) throws Exception {
|
||||
Object testInstance = context.getRequiredTestInstance();
|
||||
getContexts(testInstance).forEach((springTestContext) -> springTestContext.setTest(testInstance));
|
||||
}
|
||||
|
||||
private static List<SpringTestContext> getContexts(Object test) throws IllegalAccessException {
|
||||
Field[] declaredFields = test.getClass().getDeclaredFields();
|
||||
List<SpringTestContext> result = new ArrayList<>();
|
||||
for (Field field : declaredFields) {
|
||||
if (SpringTestContext.class.isAssignableFrom(field.getType())) {
|
||||
result.add((SpringTestContext) field.get(test));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package sample.util;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||
import org.springframework.security.oauth2.core.oidc.OidcScopes;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
|
||||
|
||||
/**
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
public class RegisteredClients {
|
||||
// @formatter:off
|
||||
public static RegisteredClient messagingClient() {
|
||||
return RegisteredClient.withId(UUID.randomUUID().toString())
|
||||
.clientId("messaging-client")
|
||||
.clientSecret("{noop}secret")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
|
||||
.redirectUri("http://127.0.0.1:8080/authorized")
|
||||
.scope(OidcScopes.OPENID)
|
||||
.scope("message.read")
|
||||
.scope("message.write")
|
||||
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
|
||||
.build();
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
Reference in New Issue
Block a user