Skip to content

Commit

Permalink
Merge pull request #19 from nla/develop/FOLIOINT-370
Browse files Browse the repository at this point in the history
Develop/folioint 370
  • Loading branch information
scott-yeadon authored Aug 13, 2024
2 parents 0ee3816 + 7578415 commit cb95f15
Show file tree
Hide file tree
Showing 17 changed files with 724 additions and 82 deletions.
42 changes: 42 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/

### VS Code ###
.vscode/

## props (with passwords)

src/main/resources/static/application.properties
application-local.properties
/releases/
run.sh
deployAndRunVoyagerLoader.sh
justRunAlreadyDeployedVoyagerLoader.sh
44 changes: 41 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.1</version>
<version>3.3.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>au.gov.nla</groupId>
<artifactId>folio-pickslip-viewer</artifactId>
<version>1.0.5-SNAPSHOT</version>
<version>1.1.0-SNAPSHOT</version>
<name>folio-pickslip-viewer</name>
<description>FOLIO pickslip / request queue viewer</description>
<properties>
Expand Down Expand Up @@ -62,6 +62,31 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
</dependency>
<!--dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency-->

<dependency>
<groupId>org.webjars</groupId>
Expand All @@ -87,10 +112,17 @@
<version>5.2.2</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.17.1</version>
</dependency>


<dependency>
<groupId>au.gov.nla</groupId>
<artifactId>folio-api</artifactId>
<version>1.0.15-RELEASE</version>
<version>1.0.21-RELEASE</version>
</dependency>

<dependency>
Expand All @@ -109,6 +141,12 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.32</version>
<scope>provided</scope>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package au.gov.nla.pickslip.config;

import lombok.AllArgsConstructor;
import lombok.NonNull;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toSet;

@AllArgsConstructor
@Component
public class KeycloakJwtAuthenticationConverter implements Converter<Jwt,
AbstractAuthenticationToken> {

@Override
public AbstractAuthenticationToken convert(@NonNull Jwt source) {
return new JwtAuthenticationToken(source,
Stream.concat(new JwtGrantedAuthoritiesConverter().convert(source)
.stream(), extractResourceRoles(source).stream())
.collect(toSet()));
}

private Collection<? extends GrantedAuthority> extractResourceRoles(Jwt jwt) {
if (jwt.hasClaim("realm_access")) {
List<String> roleList =
new HashMap<String, List<String>>(jwt.getClaim("realm_access")).get("roles");
return roleList.isEmpty() ? Collections.emptySet() : roleList.stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role.toUpperCase()))
.collect(toSet());
}
return Collections.emptySet();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package au.gov.nla.pickslip.config;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
import org.springframework.web.util.UriComponentsBuilder;

@Component
@Slf4j
public class KeycloakLogoutHandler implements LogoutHandler {

private final RestClient restClient = RestClient.create();

@Override
public void logout(
HttpServletRequest request, HttpServletResponse response, Authentication auth) {
logoutFromKeycloak((OidcUser) auth.getPrincipal());
}

private void logoutFromKeycloak(OidcUser user) {
String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
UriComponentsBuilder builder =
UriComponentsBuilder.fromUriString(endSessionEndpoint)
.queryParam("id_token_hint", user.getIdToken()
.getTokenValue());

ResponseEntity<String> result = restClient.get()
.uri(builder.toUriString())
.retrieve()
.toEntity(String.class);

if (result.getStatusCode()
.is2xxSuccessful()) {
log.info("Keycloak logout successful: {}", user.getPreferredUsername());
}
else {
log.warn("Keycloak logout unsuccessful: {}", result.getBody());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package au.gov.nla.pickslip.config;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import java.util.Arrays;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(
securedEnabled = true,
jsr250Enabled = true)
@Slf4j
@RequiredArgsConstructor
public class SecurityConfiguration {
static String[] ANONYMOUS_PATHS = {"/export/**", "/bulkprint/**", "/location/**", "/", "/home",
"/user/**", "/webjars/**", "/css/**"};

private final KeycloakLogoutHandler keycloakLogoutHandler;


@Bean
public SecurityFilterChain filterChain(final HttpSecurity http) throws Exception {
http.authorizeHttpRequests(
authorizeHttpRequests ->
authorizeHttpRequests
.requestMatchers(Arrays.stream(ANONYMOUS_PATHS)
.map(AntPathRequestMatcher::antMatcher)
.toArray(AntPathRequestMatcher[]::new))
.permitAll()
.anyRequest()
.authenticated())
.oauth2Login(Customizer.withDefaults())
.logout(logout -> logout.addLogoutHandler(keycloakLogoutHandler)
.logoutSuccessUrl("/"));
return http.build();
}
}
Loading

0 comments on commit cb95f15

Please sign in to comment.