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 authentication with Solace PubSub+ Broker. #133

Merged
merged 13 commits into from
Jul 18, 2024
Merged
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
27 changes: 26 additions & 1 deletion .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,23 @@ name: build
on:
pull_request:
push:
workflow_dispatch:

jobs:
build:
dupe_check:
name: Check for Duplicate Workflow Run
runs-on: ubuntu-latest
outputs:
should_skip: ${{ steps.skip_check.outputs.should_skip }}
steps:
- id: skip_check
uses: fkirc/[email protected]
with:
concurrent_skipping: same_content
do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]'

build:
if: needs.dupe_check.outputs.should_skip != 'true'
runs-on: ubuntu-latest

steps:
Expand All @@ -18,7 +31,19 @@ jobs:
with:
distribution: 'zulu'
java-version: '17'
overwrite-settings: false
cache: 'maven'
- name: Manually Install Test Support If Necessary
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
run: |
sudo apt-get update -qq
sudo apt-get install -y libxml2-utils
version="$(xmllint --xpath '/*[local-name()="project"]/*[local-name()="properties"]/*[local-name()="solace.integration.test.support.version"]/text()' pom.xml)"
echo "Detected test support version: ${version}"

git clone --depth 1 --branch "${version}" https://github.com/SolaceDev/solace-integration-test-support.git
cd "${GITHUB_WORKSPACE}/solace-integration-test-support"
mvn install -Dchangelist= -DskipTests
- name: Build and run Tests
run: mvn clean verify --settings "${GITHUB_WORKSPACE}/maven/settings.xml"
env:
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ solace-spring-boot-build (root)
--> solace-java-sample-app
--> solace-jms-sample-app
--> solace-jms-sample-app-jndi
--> solace-java-oauth2-sample-app

Where:
<-- indicates the parent of the project
Expand Down
9 changes: 0 additions & 9 deletions maven/settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,5 @@
<username>${env.GITHUB_ACTOR}</username>
<password>${env.GITHUB_TOKEN}</password>
</server>
<server>
<id>ossrh</id>
<username>${env.MAVEN_OSSRH_USER}</username>
<password>${env.MAVEN_OSSRH_PASS}</password>
</server>
<server>
<id>gpg.passphrase</id>
<passphrase>${env.GPG_PASSPHRASE}</passphrase>
</server>
</servers>
</settings>
21 changes: 16 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>com.solace.spring.boot</groupId>
<artifactId>solace-spring-boot-build</artifactId>
<version>2.0.1-SNAPSHOT</version>
<version>2.1.0-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Solace Spring Boot Build</name>
Expand All @@ -15,12 +15,14 @@
<repoName>SolaceProducts</repoName>

<!-- This is the version of Spring Boot we have targeted for this build -->
<spring.boot.version>3.0.6</spring.boot.version>
<spring.boot.version>3.3.1</spring.boot.version>

<solace.spring.boot.java-starter.version>5.0.1-SNAPSHOT
<solace.spring.boot.java-starter.version>5.1.0-SNAPSHOT
</solace.spring.boot.java-starter.version>
<solace.spring.boot.jms-starter.version>5.0.1-SNAPSHOT</solace.spring.boot.jms-starter.version>
<solace.spring.boot.starter.version>2.0.1-SNAPSHOT</solace.spring.boot.starter.version>
<solace.spring.boot.jms-starter.version>5.1.0-SNAPSHOT</solace.spring.boot.jms-starter.version>
<solace.spring.boot.starter.version>2.1.0-SNAPSHOT</solace.spring.boot.starter.version>
<testcontainers.version>1.19.8</testcontainers.version>
<solace.integration.test.support.version>1.1.2</solace.integration.test.support.version>
</properties>

<licenses>
Expand Down Expand Up @@ -54,6 +56,7 @@
<module>solace-spring-boot-samples/solace-java-sample-app</module>
<module>solace-spring-boot-samples/solace-jms-sample-app</module>
<module>solace-spring-boot-samples/solace-jms-sample-app-jndi</module>
<module>solace-spring-boot-samples/solace-java-oauth2-sample-app</module>
<module>solace-spring-boot-starters/solace-java-spring-boot-starter</module>
<module>solace-spring-boot-starters/solace-jms-spring-boot-starter</module>
<module>solace-spring-boot-starters/solace-spring-boot-starter</module>
Expand Down Expand Up @@ -85,6 +88,14 @@
<artifactId>solace-java-spring-boot-starter</artifactId>
<version>${solace.spring.boot.java-starter.version}</version>
</dependency>

<dependency>
<groupId>com.solace.test.integration</groupId>
<artifactId>solace-integration-test-support-bom</artifactId>
<version>${solace.integration.test.support.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
<parent>
<groupId>com.solace.spring.boot</groupId>
<artifactId>solace-spring-boot-parent</artifactId>
<version>2.0.1-SNAPSHOT</version>
<version>2.1.0-SNAPSHOT</version>
<relativePath>../../solace-spring-boot-parent/pom.xml</relativePath>
</parent>

<artifactId>solace-java-spring-boot-autoconfigure</artifactId>
<version>5.0.1-SNAPSHOT</version>
<version>5.1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>Solace Spring Boot Autoconfiguration - Java</name>
Expand All @@ -34,16 +34,61 @@
<version>${solace.jcsmp.version}</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
<optional>true</optional>
</dependency>


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-rules</artifactId>
<version>1.19.0</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit-pioneer</groupId>
<artifactId>junit-pioneer</artifactId>
<version>1.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.solace.test.integration</groupId>
<artifactId>pubsubplus-junit-jupiter</artifactId>
<version>${solace.integration.test.support.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import com.solacesystems.jcsmp.JCSMPChannelProperties;
import com.solacesystems.jcsmp.JCSMPProperties;
import com.solacesystems.jcsmp.SolaceSessionOAuth2TokenProvider;
import com.solacesystems.jcsmp.SpringJCSMPFactory;
import java.util.Map;
import java.util.Map.Entry;
Expand All @@ -33,12 +34,15 @@
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.lang.Nullable;

@Configuration
@AutoConfigureBefore(JmsAutoConfiguration.class)
@ConditionalOnClass({JCSMPProperties.class})
@ConditionalOnMissingBean(SpringJCSMPFactory.class)
@EnableConfigurationProperties(SolaceJavaProperties.class)
@Import(SolaceOAuthClientConfiguration.class)
public class SolaceJavaAutoConfiguration {

private SolaceJavaProperties properties;
Expand All @@ -54,8 +58,9 @@ public SolaceJavaAutoConfiguration(SolaceJavaProperties properties) {
* @return {@link SpringJCSMPFactory} based on {@link JCSMPProperties} bean.
*/
@Bean
public SpringJCSMPFactory getSpringJCSMPFactory(JCSMPProperties jcsmpProperties) {
return new SpringJCSMPFactory(jcsmpProperties);
public SpringJCSMPFactory getSpringJCSMPFactory(JCSMPProperties jcsmpProperties,
@Nullable SolaceSessionOAuth2TokenProvider solaceSessionOAuth2TokenProvider) {
return new SpringJCSMPFactory(jcsmpProperties, solaceSessionOAuth2TokenProvider);
}

/**
Expand Down Expand Up @@ -87,6 +92,12 @@ public JCSMPProperties getJCSMPProperties() {
cp.setReconnectRetries(properties.getReconnectRetries());
cp.setConnectRetriesPerHost(properties.getConnectRetriesPerHost());
cp.setReconnectRetryWaitInMillis(properties.getReconnectRetryWaitInMillis());

if (properties.getOauth2ClientRegistrationId() != null) {
jcsmpProps.setProperty(SolaceJavaProperties.SPRING_OAUTH2_CLIENT_REGISTRATION_ID,
properties.getOauth2ClientRegistrationId());
}

return jcsmpProps;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
@ConfigurationProperties("solace.java")
public class SolaceJavaProperties {

public static final String SPRING_OAUTH2_CLIENT_REGISTRATION_ID = "SPRING_OAUTH2_CLIENT_REGISTRATION_ID";

/**
* Solace Message Router Host address. Port is optional and intelligently defaulted by the Solace Java API.
*/
Expand Down Expand Up @@ -99,7 +101,22 @@ public class SolaceJavaProperties {
*/
private final Map<String,String> apiProperties = new ConcurrentHashMap<>();

/**
* The Spring Security OAuth2 Client Registration Id
* <code>spring.security.oauth2.client.registration.&lt;registration-id&gt;</code> to use for OAuth2
* token
* retrieval. This field is required when the Solace session is configured to use OAuth2 via
* <code>solace.java.apiProperties.authentication_scheme=AUTHENTICATION_SCHEME_OAUTH2</code>
*/
private String oauth2ClientRegistrationId;

public String getOauth2ClientRegistrationId() {
return oauth2ClientRegistrationId;
}

public void setOauth2ClientRegistrationId(String oauth2ClientRegistrationId) {
this.oauth2ClientRegistrationId = oauth2ClientRegistrationId;
}

public String getHost() {
return host;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.solace.spring.boot.autoconfigure;

import com.solacesystems.jcsmp.DefaultSolaceSessionOAuth2TokenProvider;
import com.solacesystems.jcsmp.JCSMPProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;

/**
* Configuration class for Solace OAuth client. This configuration is only active when the
* 'solace.java.apiProperties.AUTHENTICATION_SCHEME' property is set to
* 'AUTHENTICATION_SCHEME_OAUTH2'.
*/
@Configuration
@ConditionalOnProperty(prefix = "solace.java.apiProperties", name = "AUTHENTICATION_SCHEME",
havingValue = "AUTHENTICATION_SCHEME_OAUTH2")
@Import(OAuth2ClientAutoConfiguration.class)
public class SolaceOAuthClientConfiguration {

/**
* Creates and configures an OAuth2AuthorizedClientManager for Solace session. This manager is
* configured with OAuth2AuthorizedClientProvider for client credentials and refresh token.
*
* @param clientRegistrationRepository Repository of client registrations.
* @param oAuth2AuthorizedClientService Service for authorized OAuth2 clients.
* @return Configured OAuth2AuthorizedClientManager.
*/
@Bean
public AuthorizedClientServiceOAuth2AuthorizedClientManager solaceOAuthAuthorizedClientServiceAndManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientService oAuth2AuthorizedClientService) {
final OAuth2AuthorizedClientProvider clientCredentialsAuthorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.clientCredentials()
.refreshToken()
.build();

final AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager =
new AuthorizedClientServiceOAuth2AuthorizedClientManager(
clientRegistrationRepository, oAuth2AuthorizedClientService);
authorizedClientManager.setAuthorizedClientProvider(clientCredentialsAuthorizedClientProvider);

return authorizedClientManager;
}

/**
* Creates a SolaceSessionOAuth2TokenProvider for providing OAuth2 access tokens for Solace
* sessions.
*
* @param jcsmpProperties The JCSMP properties.
* @param solaceOAuthAuthorizedClientServiceAndManager The OAuth2AuthorizedClientManager for
* Solace session.
* @return Configured SolaceSessionOAuth2TokenProvider.
*/
@Bean
public DefaultSolaceSessionOAuth2TokenProvider solaceSessionOAuth2TokenProvider(
JCSMPProperties jcsmpProperties,
AuthorizedClientServiceOAuth2AuthorizedClientManager solaceOAuthAuthorizedClientServiceAndManager) {
return new DefaultSolaceSessionOAuth2TokenProvider(jcsmpProperties,
solaceOAuthAuthorizedClientServiceAndManager);
}
}
Loading