Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OAuth2 support for config clients. #2369

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions docs/modules/ROOT/pages/client.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,80 @@ spring:

----

If the config server requires OAuth2 JWT security, clients can provide the following combinations of properties.

For client credentials grant type:
----
spring:
cloud:
config:
oauth2:
token-uri: http://localhost:9080/realms/${realm}/protocol/openid-connect/token
client-id: oauth2-client
client-secret: oauth2-client-secret
grant-type: client_credentials
----

For password credentials grant type you can include username and password
----
spring:
cloud:
config:
oauth2:
token-uri: http://localhost:9080/realms/${realm}/protocol/openid-connect/token
client-id: oauth2-client
client-secret: oauth2-client-secret
grant-type: client_credentials
username: actuator-user
password: actuator-secret
----

Additionally, client-secret and password can be encrypted with http://www.jasypt.org/index.html[Jasypt].
----
spring:
cloud:
config:
encryptor:
encryptor-algorithm: PBEWITHHMACSHA512ANDAES_256
encryptor-iterations: 1000
----
The Jasypt encryption password will need to be passed as a system property. Examples:
----
-Djasypt.encryptor.password=my-favorite-password
----
It can also be done in the Spring Application.
----
import org.springframework.cloud.config.client.EncryptorConfig;

@EnableEncryptableProperties //enable Jayspt encryption
@SpringBootApplication
public class MyBootApplication {

public static void main(String[] args) {
System.setProperty(EncryptorConfig.ENCRYPTOR_SYSTEM_PROPERTY, "my-favorite-password");
//OR
System.setProperty("jasypt.encryptor.password", "my-favorite-password");
SpringApplication.run(MyBootApplication.class, args);
}
}
----
Example of OAuth2 properties with encryption.
----
spring:
cloud:
config:
oauth2:
token-uri: http://localhost:9080/realms/${realm}/protocol/openid-connect/token
client-id: oauth2-client
client-secret: ENC(WzBZMDgGCSqGSIb3DQEFDDArBBSNIl7Wk7QOYfVUgZwVvAt9kXw8QgICEAACASAwDAYIKoZIhvcNAgsFADAdBglghk=)
grant-type: client_credentials
username: actuator-user
password: ENC(7QOYfVUgZwVvAt9kXw8QgICEAACASAwDAYIKoZIhvcNAgsFADAdBglghkWzBZMDgGCSqGSIb3DQEFDDArBBSNIl7Wk==)
encryptor:
encryptor-algorithm: PBEWITHHMACSHA512ANDAES_256
encryptor-iterations: 1000
----

If config server requires client side TLS certificate, you can configure client side TLS certificate and trust store via properties, as shown in following example:

[source,yaml]
Expand Down
25 changes: 25 additions & 0 deletions spring-cloud-config-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
]]>
</description>

<properties>
<jasypt-spring-boot.version>3.0.5</jasypt-spring-boot.version>
<java-jwt.version>4.4.0</java-jwt.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down Expand Up @@ -80,6 +85,16 @@
<artifactId>spring-boot-autoconfigure-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot</artifactId>
<version>${jasypt-spring-boot.version}</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${java-jwt.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand All @@ -95,6 +110,16 @@
<artifactId>spring-cloud-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2013-2019 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 org.springframework.cloud.config.client;

import com.fasterxml.jackson.annotation.JsonProperty;

/**
* @author Bruce Randall
*
*/
public class AccessTokenResponse {

@JsonProperty("access_token")
private String accessToken;

@JsonProperty("token_type")
private String tokenType;

public String getAccessToken() {
return accessToken;
}

public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}

public String getTokenType() {
return tokenType;
}

public void setTokenType(String tokenType) {
this.tokenType = tokenType;
}

public String getBearerHeader() {
return getTokenType() + " " + getAccessToken();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Copyright 2013-2019 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 org.springframework.cloud.config.client;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
* @author Bruce Randall
*
*/
@ConfigurationProperties(ConfigClientOAuth2Properties.PREFIX)
public class ConfigClientOAuth2Properties {

/**
* Prefix for Spring Cloud Config properties.
*/
public static final String PREFIX = "spring.cloud.config.oauth2";

/**
* The OAuth2 token URI of the IDP issuing JWT tokens. When present enables OAuth2
* client calls.
*/
private String tokenUri;

/**
* The OAuth2 grant type (client_credentials, password).
*/
private String grantType;

/**
* The OAuth2 client id should it be needed in JWT token request.
*/
private String clientId;

/**
* The OAuth2 client secret should it be needed in JWT token request.
*/
private String clientSecret;

/**
* The OAuth2 username to use when contacting the IDP.
*/
private String oauthUsername;

/**
* The OAuth2 user password to use when contacting the IDP.
*/
private String oauthPassword;

public String getTokenUri() {
return tokenUri;
}

public void setTokenUri(String tokenUri) {
this.tokenUri = tokenUri;
}

public String getGrantType() {
return grantType;
}

public void setGrantType(String grantType) {
this.grantType = grantType;
}

public String getClientId() {
return clientId;
}

public void setClientId(String clientId) {
this.clientId = clientId;
}

public String getClientSecret() {
return clientSecret;
}

public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}

public String getOauthUsername() {
return oauthUsername;
}

public void setOauthUsername(String oauthUsername) {
this.oauthUsername = oauthUsername;
}

public String getOauthPassword() {
return oauthPassword;
}

public void setOauthPassword(String oauthPassword) {
this.oauthPassword = oauthPassword;
}

@Override
public String toString() {
return "ConfigClientOAuth2Properties{" + "tokenUri='" + tokenUri + '\'' + ", grantType='" + grantType + '\''
+ ", clientId='" + clientId + '\'' + ", oauthUsername='" + oauthUsername + '\'' + '}';
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@ public class ConfigClientProperties {
*/
private String password;

/**
* OAUTH2 Properties.
*/
private ConfigClientOAuth2Properties configClientOAuth2Properties;

/**
* Encryption properties.
*/
private EncryptorConfig encryptorConfig;

/**
* The URI of the remote server (default http://localhost:8888).
*/
Expand Down Expand Up @@ -248,6 +258,22 @@ public void setPassword(String password) {
this.password = password;
}

public ConfigClientOAuth2Properties getConfigClientOAuth2Properties() {
return configClientOAuth2Properties;
}

public void setConfigClientOAuth2Properties(ConfigClientOAuth2Properties configClientOAuth2Properties) {
this.configClientOAuth2Properties = configClientOAuth2Properties;
}

public EncryptorConfig getEncryptorConfig() {
return encryptorConfig;
}

public void setEncryptorConfig(EncryptorConfig encryptorConfig) {
this.encryptorConfig = encryptorConfig;
}

public Credentials getCredentials(int index) {
return extractCredentials(index);
}
Expand Down
Loading
Loading