Skip to content

Commit

Permalink
Merge branch 'dev' into 30948_ANTLR4_filter_grammar
Browse files Browse the repository at this point in the history
  • Loading branch information
cgendreau committed Feb 14, 2024
2 parents b1e6ffd + 5660b18 commit d29deb1
Show file tree
Hide file tree
Showing 30 changed files with 611 additions and 21 deletions.
6 changes: 3 additions & 3 deletions dina-base-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<parent>
<groupId>io.github.aafc-bicoe</groupId>
<artifactId>dina-base-parent</artifactId>
<version>0.115-SNAPSHOT</version>
<version>0.118-SNAPSHOT</version>
</parent>

<artifactId>dina-base-api</artifactId>
Expand All @@ -25,7 +25,7 @@
<jacoco-maven-plugin.version>0.8.8</jacoco-maven-plugin.version>
<javers.version>6.13.0</javers.version>
<mybatis.version>2.2.2</mybatis.version>
<aafc.search.messaging.version>0.20</aafc.search.messaging.version>
<aafc.search.messaging.version>0.29</aafc.search.messaging.version>
<hypersistence-utils-hibernate-55.version>3.6.1</hypersistence-utils-hibernate-55.version>
<postgresql.version>42.4.3</postgresql.version>
<jsoup.version>1.15.3</jsoup.version>
Expand Down Expand Up @@ -148,7 +148,7 @@
<dependency>
<groupId>io.github.aafc-bicoe</groupId>
<artifactId>dina-test-support</artifactId>
<version>0.115-SNAPSHOT</version>
<version>0.118-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,11 @@

@SpringBootTest(classes = {TestDinaBaseApp.class, MessageProducingServiceTest.TestConfig.class},
properties = {
"messaging.isProducer=true",
"dina.messaging.isProducer=true",
"rabbitmq.queue=que",
"rabbitmq.exchange=exchange",
"rabbitmq.routingkey=routingkey",
"rabbitmq.username=guest",
"rabbitmq.password=guest",
"rabbitmq.host=localhost",
"rabbitmq.port=49198"
"rabbitmq.host=localhost"
})
@ContextConfiguration(initializers = { PostgresTestContainerInitializer.class })
@DirtiesContext //it's an expensive test and we won't reuse the context
Expand Down Expand Up @@ -197,11 +194,10 @@ public static class Listener {

@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = "que"),
exchange = @Exchange(value = "exchange", ignoreDeclarationExceptions = "true"),
key = "routingkey"),
exchange = @Exchange(value = "que", ignoreDeclarationExceptions = "true")),
containerFactory = "rabbitListenerContainerFactory"
)
public void processOrder(String data) {
public void processMessage(String data) {
messages.clear();
messages.add(data);
latch.countDown();
Expand Down
3 changes: 3 additions & 0 deletions dina-client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# DINA Client


51 changes: 51 additions & 0 deletions dina-client/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>io.github.aafc-bicoe</groupId>
<artifactId>dina-base-parent</artifactId>
<version>0.118-SNAPSHOT</version>
</parent>

<artifactId>dina-client</artifactId>
<name>dina-client</name>
<description>DINA client</description>
<url>https://github.com/AAFC-BICoE/dina-base-api</url>

<properties>
<okhttp.version>4.9.0</okhttp.version>
<retrofit.version>2.9.0</retrofit.version>
</properties>

<dependencies>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp.version}</version>
</dependency>

<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>${retrofit.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-jackson</artifactId>
<version>${retrofit.version}</version>
</dependency>
</dependencies>

<licenses>
<license>
<name>MIT License</name>
<url>https://opensource.org/licenses/mit-license</url>
<distribution>repo</distribution>
</license>
</licenses>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package ca.gc.aafc.dina.client;

import java.io.IOException;
import okhttp3.Authenticator;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.Route;

import ca.gc.aafc.dina.client.token.AccessTokenManager;

/**
* OkHttp3 Authenticator that supports OpenID Connect access token.
*
* Usage:
* OkHttpClient client = new OkHttpClient.Builder()
* .authenticator(new AccessTokenAuthenticator(new AccessTokenManager(openIdConfig)))
* .build();
*
*/
public class AccessTokenAuthenticator implements Authenticator {

private final AccessTokenManager accessTokenManager;

public AccessTokenAuthenticator(AccessTokenManager accessTokenManager) {
this.accessTokenManager = accessTokenManager;
}

@Override
public Request authenticate(Route route, Response response) {
final String accessToken;
try {
accessToken = accessTokenManager.getAccessToken();
} catch (IOException e) {
throw new RuntimeException(e);
}

if (accessToken == null) {
return null;
}

return newRequestWithBearerToken(response.request(), accessToken);
}

private Request newRequestWithBearerToken(Request request, String accessToken) {
return request.newBuilder()
.header("Authorization", "Bearer " + accessToken)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ca.gc.aafc.dina.client;

import java.io.IOException;
import okhttp3.Request;

import ca.gc.aafc.dina.client.token.AccessTokenManager;

/**
* OkHttp Request builder that will use a AccessTokenManager to create a Request
* with the Authorization header properly set.
*/
public class TokenBasedRequestBuilder {

private final AccessTokenManager accessTokenManager;

public TokenBasedRequestBuilder(AccessTokenManager accessTokenManager) {
this.accessTokenManager = accessTokenManager;
}

public Request.Builder newBuilder() throws IOException {
return new Request.Builder().header("Authorization", "Bearer " + accessTokenManager.getAccessToken());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ca.gc.aafc.dina.client.config;

import lombok.Data;

@Data
public class OpenIdConnectConfig {

/**
* for Keycloak it should look like .../realms/dina/protocol/openid-connect/
*/
private String openIdConnectBaseUrl;

private String clientId;
private String username;
private String password;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ca.gc.aafc.dina.client.token;

import lombok.Data;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

/**
* Represents an access token response from an OpenId Connect endpoint.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
@Data
public class AccessToken {

private String clientId;
private String tokenType;
private String accessToken;

private String refreshToken;
private int expiresIn;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ca.gc.aafc.dina.client.token;

import java.util.Map;
import retrofit2.Call;
import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;

/**
* Retrofit based API call to an OpenId Connect endpoint to get or refresh tokens.
*/
public interface AccessTokenApiCall {

@FormUrlEncoded
@POST("token")
Call<AccessToken> callAccessTokenEndpoint(@FieldMap Map<String, Object> accessTokenRequest);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package ca.gc.aafc.dina.client.token;

import ca.gc.aafc.dina.client.config.OpenIdConnectConfig;

import java.io.IOException;
import java.time.Instant;
import lombok.extern.log4j.Log4j2;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.jackson.JacksonConverterFactory;

/**
* Encapsulate the logic to acquire and refresh tokens.
*/
@Log4j2
public class AccessTokenManager {

private static final int BUFFER_IN_SEC = 10;

private final AccessTokenApiCall accessTokenApiCall;
private final OpenIdConnectConfig config;

private String accessToken;
// in seconds
private int expiresIn;
private String refreshToken;
private Instant tokenInstant;

public AccessTokenManager(OpenIdConnectConfig openIdConnectConfig) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(openIdConnectConfig.getOpenIdConnectBaseUrl())
.addConverterFactory(JacksonConverterFactory.create())
.build();

accessTokenApiCall = retrofit.create(AccessTokenApiCall.class);
this.config = openIdConnectConfig;
}

public synchronized String getAccessToken() throws IOException {

// check if we already have a token
if (accessToken == null) {
acquireAccessToken();
return accessToken;
}

boolean isAlmostExpired = Instant.now().isAfter(tokenInstant.plusSeconds(expiresIn - BUFFER_IN_SEC));
if(!isAlmostExpired) {
return accessToken;
} else {
if(!refreshAccessToken()) {
acquireAccessToken();
}
}

return accessToken;
}

private boolean acquireAccessToken() throws IOException {
log.debug("Acquire token");
Call<AccessToken> accessTokenCall = accessTokenApiCall.callAccessTokenEndpoint(
AccessTokenRequest.newPasswordBased(config).toFieldMap());
Response<AccessToken> accessTokenResponse = accessTokenCall.execute();

if(!accessTokenResponse.isSuccessful()) {
accessToken = null;
return false;
}

AccessToken token = accessTokenResponse.body();
accessToken = token.getAccessToken();
expiresIn = token.getExpiresIn();
refreshToken = token.getRefreshToken();
tokenInstant = Instant.now();
return true;
}

private boolean refreshAccessToken() throws IOException {
log.debug("Refresh token");

Call<AccessToken> accessTokenCall = accessTokenApiCall.callAccessTokenEndpoint(
AccessTokenRequest.newRefreshTokenBased(config.getClientId(), refreshToken)
.toFieldMap());

Response<AccessToken> accessTokenResponse = accessTokenCall.execute();
log.debug("Refreshing token successful: {}", accessTokenResponse::isSuccessful);

if(!accessTokenResponse.isSuccessful()) {
return false;
}

AccessToken token = accessTokenResponse.body();
accessToken = token.getAccessToken();
expiresIn = token.getExpiresIn();
refreshToken = token.getRefreshToken();
tokenInstant = Instant.now();
return true;
}
}
Loading

0 comments on commit d29deb1

Please sign in to comment.