Skip to content

Commit

Permalink
Merge pull request #10 from OpenConext/develop
Browse files Browse the repository at this point in the history
Prepare release 2.3.0
  • Loading branch information
tbeekman authored May 29, 2024
2 parents 46d4da3 + f6aab99 commit ac25d26
Show file tree
Hide file tree
Showing 15 changed files with 184 additions and 131 deletions.
32 changes: 1 addition & 31 deletions oc-sso-notificatie/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,13 @@
<parent>
<artifactId>oc-sso-notificatie-parent</artifactId>
<groupId>nl.kennisnet.services</groupId>
<version>2.2.1</version>
<version>2.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>oc-sso-notificatie</artifactId>
<name>OC SSO Notification - Application</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<server.tomcat.uri-encoding>UTF-8</server.tomcat.uri-encoding>
<timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
<checkstyle.plugin.version>3.1.0</checkstyle.plugin.version>
<logback.encoder.version>5.3</logback.encoder.version>
<lombok.version>1.18.20</lombok.version>
<maven.deploy.skip>false</maven.deploy.skip>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down Expand Up @@ -67,12 +56,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.vaadin.external.google</groupId>
<artifactId>android-json</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
Expand All @@ -92,18 +75,6 @@
<version>${lombok.version}</version>
</dependency>

<!-- Required dependencies - not available in OpenJDK 11 -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${javax.bind}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>

<build>
Expand All @@ -118,7 +89,6 @@
</goals>
<configuration>
<additionalProperties>
<time>${maven.build.timestamp}</time>
<java_version>${java.version}</java_version>
<spring_boot_version>${project.parent.parent.version}</spring_boot_version>
</additionalProperties>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package nl.kennisnet.services.actuator;

import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.boot.info.BuildProperties;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;

@Component
public class ReleaseDaysInfoContributor implements InfoContributor {

private static final String RELEASE_DAYS_KEY = "days_since_release";

private final BuildProperties buildProperties;

public ReleaseDaysInfoContributor(BuildProperties buildProperties) {
this.buildProperties = buildProperties;
}

@Override
public void contribute(Info.Builder builder) {
long currentDays = 0L;

if (null != buildProperties.getTime()) {
LocalDate releaseDate = LocalDate.ofInstant(buildProperties.getTime(), ZoneId.systemDefault());
LocalDate currentDate = LocalDate.ofInstant(Instant.now(), ZoneId.systemDefault());
currentDays = ChronoUnit.DAYS.between(releaseDate, currentDate);
}
builder.withDetail(RELEASE_DAYS_KEY, currentDays);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

/**
* Guava cache configuration.
*/
@Configuration
@EnableCaching
@EnableScheduling
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.springframework.beans.factory.annotation.Value;
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;
Expand All @@ -42,20 +43,21 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// This application only contains public pages. The Spring Boot Actuator Endpoints can be protected by the
// config in Spring Boot Actuator Endpoints.
if (null != managementSecurityRoles) {
http.authorizeHttpRequests()
.requestMatchers("/actuator/**").hasRole(managementSecurityRoles)
.anyRequest().permitAll();

http.httpBasic();
http.authorizeHttpRequests(authz -> authz
.requestMatchers("/actuator/**").hasRole(managementSecurityRoles)
.anyRequest().permitAll()
).httpBasic(Customizer.withDefaults());
} else {
http.authorizeHttpRequests().anyRequest().permitAll();
http.authorizeHttpRequests(authz -> authz
.anyRequest().permitAll());
}

// We have to disable the X-Frame-Options since this SSO Notification service can be invoked within an iframe.
http.headers().frameOptions().disable();

// Disable all security headers so this service can be invoked within 3rd-party applications.
http.headers().disable();
http.headers(headers -> headers
.frameOptions(Customizer.withDefaults())
.disable());

return http.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@
package nl.kennisnet.services.web.controller;

import nl.kennisnet.services.web.config.CacheConfig;
import nl.kennisnet.services.web.exception.NoMatchFoundException;
import nl.kennisnet.services.web.model.IdP;
import nl.kennisnet.services.web.service.CookiesHandler;
import nl.kennisnet.services.web.service.IdPProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
Expand All @@ -37,9 +35,6 @@
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
Expand Down Expand Up @@ -93,9 +88,6 @@ public class SsoNotificationController {
/** The name of the SSO Cookie notification ({@value}) */
public static final String COOKIE_NOTIFICATION = "ssonot";

@Value("${passthru.endpoint:#{null}}")
private String passthruEndpoint;

private final CacheConfig cacheConfig;

private final CookiesHandler cookiesHandler;
Expand Down Expand Up @@ -137,7 +129,7 @@ public void processSsoNotification(@RequestParam(required = false) String id,
throws IOException {

LOGGER.info("Request received with id ('{}') url ('{}') redirectUri ('{}') referrer ('{}') realm ('{}') " +
"notificationCookie ('{}')", id, url, redirectUri, referrer, realm, notificationCookie);
"notificationCookie ('{}')", id, url, redirectUri, referrer, realm, notificationCookie);

// Add IdP id to logback and set default to failed
MDC.put(IDP, String.valueOf(id));
Expand All @@ -160,21 +152,9 @@ public void processSsoNotification(@RequestParam(required = false) String id,
}

IdP idp = ssoNotifications.stream().filter(p -> p.getEntityId().equalsIgnoreCase(id)).findAny().orElse(null);
try {
verifyIdP(idp, id, redirectUri);
} catch (NoMatchFoundException nmfe) {
if (null != passthruEndpoint) {
EVENT_LOGGER.info("No match found for id ('{}'). Redirecting to passthru", id);
LOGGER.info("No match found for id ('{}'). Redirecting to passthru", id);
response.sendRedirect(MessageFormat.format(passthruEndpoint, encodeParam(id), encodeParam(url),
encodeParam(redirectUri)));

if (null != referrer) {
response.setHeader(HttpHeaders.REFERER, referrer);
}
return;
}
}

verifyIdP(idp, id, redirectUri);

URL createdUrl = determineAndVerifyURL(idp, url, referrer);

// Set notification cookie
Expand Down Expand Up @@ -240,32 +220,25 @@ private URL verifyUrl(List<String> configuredUrlReferrers, String url, String co
* @param redirectUri the redirect URL used (OPTIONAL)
*
* @throws ResponseStatusException if the idp is invalid.
* @throws NoMatchFoundException if the idp was not found and confederational redirects are enabled
*/
private void verifyIdP(IdP idp, String id, String redirectUri) throws NoMatchFoundException {
private void verifyIdP(IdP idp, String id, String redirectUri) {
if (null == id) {
EVENT_LOGGER.warn(EXCEPTION_ID_NOT_PROVIDED);
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, EXCEPTION_ID_NOT_PROVIDED);
}

if (id.length() == 0) {
if (id.isEmpty()) {
EVENT_LOGGER.warn(EXCEPTION_ID_EMPTY);
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, EXCEPTION_ID_EMPTY);
}

if (null == idp) {
EVENT_LOGGER.warn("Unknown 'id' parameter found in request: {}", id);
if (null != passthruEndpoint) {
throw new NoMatchFoundException();
}
throw new ResponseStatusException(HttpStatus.FORBIDDEN, EXCEPTION_UNKNOWN_ID + id);
}

if (CollectionUtils.isEmpty(idp.getIdpUrlList())) {
EVENT_LOGGER.warn("No valid URL expression associated with the IdP available for IdP with ID: {}", id);
if (null != passthruEndpoint) {
throw new NoMatchFoundException();
}
throw new ResponseStatusException(HttpStatus.FORBIDDEN, EXCEPTION_NO_VALID_URL_EXPRESSION_IDP + id);
}

Expand Down Expand Up @@ -335,8 +308,4 @@ private URL determineAndVerifyURL(IdP idp, String url, String referrer) {
}
return result;
}

private String encodeParam(String param) {
return (null != param && param.length() > 0) ? URLEncoder.encode(param, StandardCharsets.UTF_8) : "";
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package nl.kennisnet.services.web.service;

import org.apache.tomcat.util.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
Expand All @@ -35,6 +34,7 @@
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Base64;

/**
* Encrypts data using algorithm and secured key from properties
Expand Down Expand Up @@ -83,10 +83,9 @@ public String encrypt(String data) {
.put(enc)
.array();

byte[] b64 = Base64.encodeBase64(cipherText, false);
return new String(b64, StandardCharsets.UTF_8);
return Base64.getEncoder().encodeToString(cipherText);
} catch (Exception ex) {
LOGGER.error("Encryption error: {} trace: {}", ex.getMessage() , ex);
LOGGER.error("Encryption error: {}", ex.getMessage() , ex);
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Strings;
import nl.kennisnet.services.web.config.CacheConfig;
import nl.kennisnet.services.web.model.IdP;
import org.slf4j.Logger;
Expand Down Expand Up @@ -88,8 +87,8 @@ public IdPProvider(RestTemplate restTemplate) {
*/
@Cacheable(value = CacheConfig.IDP_CACHE)
public List<IdP> getAllSsoNotifications() {
if (!Strings.isNullOrEmpty(endpointUrl) && !Strings.isNullOrEmpty(apiKeyHeaderKey) &&
!Strings.isNullOrEmpty(apiKeyHeaderValue) && !Strings.isNullOrEmpty(endpointAllSuffix)) {
if (stringIsNotNullOrEmpty(endpointUrl) && stringIsNotNullOrEmpty(apiKeyHeaderKey) &&
stringIsNotNullOrEmpty(apiKeyHeaderValue) && stringIsNotNullOrEmpty(endpointAllSuffix)) {

return getAllSsoNotificationsFromDataServices();
} else {
Expand Down Expand Up @@ -135,4 +134,8 @@ private HttpHeaders constructRequestHeader() {
return requestHeaders;
}

private boolean stringIsNotNullOrEmpty(String string) {
return string != null && !string.isEmpty();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package nl.kennisnet.services.web.actuator;

import nl.kennisnet.services.actuator.ReleaseDaysInfoContributor;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.info.BuildProperties;

import java.time.Duration;
import java.time.Instant;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class ReleaseDaysInfoContributorTest {

@Mock
private BuildProperties buildProperties;

@InjectMocks
private ReleaseDaysInfoContributor infoIndicator;

@Test
void testSeveralDays() {
when(buildProperties.getTime()).thenReturn(Instant.now().minus(Duration.ofDays(3)));
Info.Builder builder = new Info.Builder();
infoIndicator.contribute(builder);
Info info = builder.build();

assertEquals(3L, info.get("days_since_release"));
}

@Test
void testZeroDays() {
when(buildProperties.getTime()).thenReturn(Instant.now());
Info.Builder builder = new Info.Builder();
infoIndicator.contribute(builder);
Info info = builder.build();

assertEquals(0L, info.get("days_since_release"));
}

@Test
void testNoBuildInfo() {
Info.Builder builder = new Info.Builder();
infoIndicator.contribute(builder);
Info info = builder.build();

assertEquals(0L, info.get("days_since_release"));
}

}
Loading

0 comments on commit ac25d26

Please sign in to comment.