Skip to content

Commit

Permalink
Merge branch 'release/6.0.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
sbearcsiro committed Jun 27, 2023
2 parents 463d3bc + 1ca1140 commit 54e5240
Show file tree
Hide file tree
Showing 12 changed files with 98 additions and 30 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ ALA plugins
Usage
-----

The current version of these libraries is: `6.0.0-SNAPSHOT`.
The current version of these libraries is: `6.0.3`.

To ensure that various plugins and libraries and self-consistent, a project should use the same version for
each of the plugins and libraries that it consumes, eg for a Grails project:

`gradle.properties`:
```gradle.properties
alaSecurityLibsVersion=6.0.0
alaSecurityLibsVersion=6.0.3
```

`build.gradle`:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ class WebService {
}
}
} catch (Exception e) {
e.printStackTrace()
// e.printStackTrace()
log.error("Failed sending ${method} request to ${url}", e)
result.statusCode = HttpStatus.SC_INTERNAL_SERVER_ERROR
result.error = "Failed calling web service. ${e.getClass()} ${e.getMessage()} URL= ${url}, method ${method}."
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package au.org.ala.ws

import au.org.ala.ws.config.AlaWsPluginConfig
import au.org.ala.ws.config.AlaWsPluginTokenServiceConfig

class AlaWsPluginGrailsPlugin {
// the version or versions of Grails the plugin is designed for
Expand Down Expand Up @@ -29,6 +30,7 @@ class AlaWsPluginGrailsPlugin {

def doWithSpring = {
alaWsPluginConfg(AlaWsPluginConfig)
alaWsPluginTokenServiceConfig(AlaWsPluginTokenServiceConfig)
}

def doWithDynamicMethods = { ctx ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

import javax.annotation.PostConstruct

@Configuration
class AlaWsPluginConfig {

Expand All @@ -39,16 +41,17 @@ class AlaWsPluginConfig {

@Bean
TokenService tokenService(
@Autowired(required = false) Config config,
@Autowired(required = false) OidcConfiguration oidcConfiguration,
@Autowired(required = false) Pac4jContextProvider pac4jContextProvider,
@Autowired(required = false) SessionStore sessionStore,
@Autowired TokenClient tokenClient
) {
new TokenService(config, oidcConfiguration, pac4jContextProvider,
// note not injecting PAC4j Config here due to potential circular dependency
new TokenService(oidcConfiguration,
sessionStore, tokenClient, clientId, clientSecret, jwtScopes, cacheTokens)
}



/**
* OK HTTP Interceptor that injects a client credentials Bearer token into a request
* @return
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package au.org.ala.ws.config


import au.org.ala.ws.tokens.TokenService
import org.pac4j.core.config.Config
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Configuration

import javax.annotation.PostConstruct

@Configuration class AlaWsPluginTokenServiceConfig {

@Autowired
TokenService tokenService
@Autowired
Config config

/**
* Injecting the PAC4j Config into the TokenService can cause a circular dependency.
* Since the Config isn't used in the construction of the TokenService, we inject
* it after construction instead.
*/
@PostConstruct
void setConfigOnTokenService() {
tokenService.setConfig(config)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ import com.nimbusds.oauth2.sdk.id.ClientID
import com.nimbusds.oauth2.sdk.token.AccessToken
import com.nimbusds.oauth2.sdk.token.RefreshToken
import groovy.util.logging.Slf4j
import org.grails.web.servlet.mvc.GrailsWebRequest
import org.grails.web.util.WebUtils
import org.pac4j.core.config.Config
import org.pac4j.core.context.WebContext
import org.pac4j.core.context.session.SessionStore
import org.pac4j.core.profile.ProfileManager
import org.pac4j.core.util.FindBest
import org.pac4j.jee.context.JEEContextFactory
import org.pac4j.oidc.config.OidcConfiguration
import org.pac4j.oidc.credentials.OidcCredentials
import org.pac4j.oidc.profile.OidcProfile
Expand All @@ -33,7 +38,8 @@ class TokenService {
final String jwtScopes
final List<String> finalScopes

private final Config config
// mutable to break circular spring dependency
Config config

private final OidcConfiguration oidcConfiguration

Expand All @@ -46,10 +52,22 @@ class TokenService {
TokenService(Config config, OidcConfiguration oidcConfiguration, Pac4jContextProvider pac4jContextProvider,
SessionStore sessionStore, TokenClient tokenClient, String clientId, String clientSecret, String jwtScopes,
boolean cacheTokens) {
this(oidcConfiguration, pac4jContextProvider, sessionStore, tokenClient, clientId, clientSecret, jwtScopes, cacheTokens)
this.config = config
}

TokenService(OidcConfiguration oidcConfiguration, Pac4jContextProvider pac4jContextProvider,
SessionStore sessionStore, TokenClient tokenClient, String clientId, String clientSecret, String jwtScopes,
boolean cacheTokens) {
this(oidcConfiguration, sessionStore, tokenClient, clientId, clientSecret, jwtScopes, cacheTokens)
this.pac4jContextProvider = pac4jContextProvider
}

TokenService(OidcConfiguration oidcConfiguration, SessionStore sessionStore, TokenClient tokenClient,
String clientId, String clientSecret, String jwtScopes, boolean cacheTokens) {
this.cacheTokens = cacheTokens
this.config = config
this.oidcConfiguration = oidcConfiguration
this.pac4jContextProvider = pac4jContextProvider
this.sessionStore = sessionStore
this.tokenClient = tokenClient

Expand All @@ -62,7 +80,15 @@ class TokenService {
}

ProfileManager getProfileManager() {
def context = pac4jContextProvider.webContext()
final WebContext context
if (pac4jContextProvider) {
context = pac4jContextProvider.webContext()
} else {
def gwr = WebUtils.retrieveGrailsWebRequest()
def request = gwr.request
def response = gwr.response
context = FindBest.webContextFactory(null, config, JEEContextFactory.INSTANCE).newContext(request, response)
}
final ProfileManager manager = new ProfileManager(context, sessionStore)
manager.config = config
return manager
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,16 @@ import au.org.ala.web.UserDetails
import au.org.ala.ws.tokens.TokenService
import com.google.common.collect.ImmutableList
import grails.converters.JSON
import grails.testing.mixin.integration.Integration
import grails.testing.services.ServiceUnitTest
import grails.util.GrailsWebMockUtil
import grails.testing.web.GrailsWebUnitTest
import groovy.json.JsonSlurper
import groovy.util.logging.Slf4j
import org.apache.http.HttpStatus
import org.apache.http.entity.ContentType
import org.grails.spring.beans.factory.InstanceFactoryBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.context.WebApplicationContext
import org.springframework.web.context.request.RequestContextHolder
import ratpack.exec.Promise
import ratpack.form.Form
import ratpack.groovy.test.embed.GroovyEmbeddedApp
import ratpack.http.Status
import ratpack.http.TypedData
import ratpack.test.embed.EmbeddedApp
import spock.lang.Ignore
Expand All @@ -29,18 +25,15 @@ import uk.org.lidalia.slf4jtest.LoggingEvent
import uk.org.lidalia.slf4jtest.TestLogger
import uk.org.lidalia.slf4jtest.TestLoggerFactory

@Integration
class WebServiceSpec extends Specification implements ServiceUnitTest<WebService> {
@Slf4j
class WebServiceSpec extends Specification implements ServiceUnitTest<WebService>, GrailsWebUnitTest {

@Shared
EmbeddedApp server

@Shared
String url

@Autowired
WebApplicationContext ctx

def setupSpec() {
/* https://ratpack.io/manual/current/all.html */
server = GroovyEmbeddedApp.of {
Expand Down Expand Up @@ -98,26 +91,24 @@ class WebServiceSpec extends Specification implements ServiceUnitTest<WebService
],
app : []
])
GrailsWebMockUtil.bindMockWebRequest(ctx)
}

def cleanupSpec() {
server?.close()
}

def cleanup() {
RequestContextHolder.resetRequestAttributes()
}

def "a request that results in a connection exception should return a statusCode == 500 and an error message, and log the error"() {
setup:
TestLogger logger = TestLoggerFactory.getTestLogger("au.org.ala.ws.service.WebService")

when: "the call results in a 404 (i.e. there is no server running)"
when: "Requesting a URL on a non existant server"
Map result = service.get("http://localhost:3123")
ImmutableList<LoggingEvent> loggingEvents = logger.getLoggingEvents()

then:
then: "the call results in a 500 (i.e. there is no server running)"
result.error != null
result.statusCode == HttpStatus.SC_INTERNAL_SERVER_ERROR

Expand Down
15 changes: 15 additions & 0 deletions ala-ws-plugin/src/test/resources/test-logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<configuration>

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>

<root level="error">
<appender-ref ref="CONSOLE"/>
</root>

</configuration>
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ public Config pac4jConfig(List<Client> clients, SessionStore sessionStore, WebCo
}

@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "security.jwt", name="enabled")
public ResourceRetriever jwtResourceRetriever() {
DefaultResourceRetriever resourceRetriever = new DefaultResourceRetriever(jwtProperties.getConnectTimeoutMs(), jwtProperties.getReadTimeoutMs());
Expand All @@ -121,6 +122,8 @@ public OidcConfiguration oidcConfiguration(ResourceRetriever jwtResourceRetrieve
}

@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "security.jwt", name = "enabled")
JWKSource<SecurityContext> jwkSource(OidcConfiguration oidcConfiguration) {
OIDCProviderMetadata providerMetadata = oidcConfiguration.findProviderMetadata();
URL keySourceUrl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public void validate(Credentials credentials, WebContext context, SessionStore s
alaApiUserProfile = fetchUserProfile(alaApiKeyCredentials.getToken());
} catch (IOException e) {
log.warn("Couldn't fetch user profile", e);
throw new CredentialsException("Coudln't fetch user profile");
throw new CredentialsException("Couldn't fetch user profile");
}

if (alaApiUserProfile.isActivated() && !alaApiUserProfile.isLocked()) {
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
projectVersion=6.0.3
projectVersion=6.0.4

org.gradle.daemon=true
org.gradle.parallel=true
Expand Down
8 changes: 4 additions & 4 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ enableFeaturePreview('VERSION_CATALOGS')
dependencyResolutionManagement {
versionCatalogs {
pac4j {
alias('oidc').to('org.pac4j:pac4j-oidc:5.7.0')
alias('jwt').to('org.pac4j:pac4j-jwt:5.7.0')
alias('http').to('org.pac4j:pac4j-http:5.7.0')
alias('jee').to('org.pac4j:pac4j-javaee:5.7.0')
alias('oidc').to('org.pac4j:pac4j-oidc:5.7.1')
alias('jwt').to('org.pac4j:pac4j-jwt:5.7.1')
alias('http').to('org.pac4j:pac4j-http:5.7.1')
alias('jee').to('org.pac4j:pac4j-javaee:5.7.1')
alias('jee-support').to('org.pac4j:javaee-pac4j:7.1.0')
}
}
Expand Down

0 comments on commit 54e5240

Please sign in to comment.