Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 17873adf1f | |||
| a608352689 | |||
| c3dbbb2d01 | |||
| 9a5319d5a2 | |||
| 0af0751cfd | |||
| 39dbd24dcb | |||
| 33ebd5405a | |||
| 2d2c2d31fa | |||
| 6c9efc2f09 | |||
| 1a163dca37 | |||
| 1b0c4d68da | |||
| b38b495630 | |||
| c8a0601e6a | |||
| 2c9dc08e43 | |||
| 5a7f12f1a9 | |||
| 3b355a0278 | |||
| a6d362fa18 | |||
| 37984c2e11 | |||
| b3a43d6154 | |||
| a87fc4ea8a | |||
| e7bff4240a | |||
| 4e6b8e4d29 | |||
| e550c48180 | |||
| a3c06d98ca | |||
| 8f42c86a57 | |||
| 5dae6da15a | |||
| e1c4177cd8 | |||
| c2e97d7661 | |||
| 94a66f7a26 | |||
| 5f80468de3 | |||
| 2f762fefe1 | |||
| 45c37c4454 | |||
| 0c70f358d5 | |||
| 7d38686e09 | |||
| 8b9beb0e1f |
@@ -1,13 +1,52 @@
|
||||
name: Merge Dependabot PR
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
on: pull_request_target
|
||||
|
||||
run-name: Merge Dependabot PR ${{ github.ref_name }}
|
||||
|
||||
permissions: write-all
|
||||
|
||||
jobs:
|
||||
merge-dependabot-pr:
|
||||
permissions: write-all
|
||||
uses: spring-io/spring-github-workflows/.github/workflows/spring-merge-dependabot-pr.yml@1e8b0587a1f4f01697f9753fa3339c3e0d30f396
|
||||
with:
|
||||
mergeArguments: '--auto --rebase'
|
||||
runs-on: ubuntu-latest
|
||||
if: github.actor == 'dependabot[bot]'
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
show-progress: false
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 17
|
||||
|
||||
- name: Set Milestone to Dependabot Pull Request
|
||||
id: set-milestone
|
||||
run: |
|
||||
if test -f pom.xml
|
||||
then
|
||||
CURRENT_VERSION=$(mvn help:evaluate -Dexpression="project.version" -q -DforceStdout)
|
||||
else
|
||||
CURRENT_VERSION=$(cat gradle.properties | sed -n '/^version=/ { s/^version=//;p }')
|
||||
fi
|
||||
export CANDIDATE_VERSION=${CURRENT_VERSION/-SNAPSHOT}
|
||||
MILESTONE=$(gh api repos/$GITHUB_REPOSITORY/milestones --jq 'map(select(.due_on != null and (.title | startswith(env.CANDIDATE_VERSION)))) | .[0] | .title')
|
||||
|
||||
if [ -z $MILESTONE ]
|
||||
then
|
||||
gh run cancel ${{ github.run_id }}
|
||||
echo "::warning title=Cannot merge::No scheduled milestone for $CURRENT_VERSION version"
|
||||
else
|
||||
gh pr edit ${{ github.event.pull_request.number }} --milestone $MILESTONE
|
||||
echo mergeEnabled=true >> $GITHUB_OUTPUT
|
||||
fi
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Merge Dependabot pull request
|
||||
if: steps.set-milestone.outputs.mergeEnabled
|
||||
run: gh pr merge ${{ github.event.pull_request.number }} --auto --rebase
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
||||
|
||||
@@ -148,5 +148,6 @@ tasks.register('cloneSamples', IncludeRepoTask) {
|
||||
}
|
||||
|
||||
s101 {
|
||||
repository = 'https://structure101.com/binaries/latest'
|
||||
configurationDirectory = project.file("etc/s101")
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,6 @@
|
||||
package s101;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -34,18 +33,11 @@ import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import com.gargoylesoftware.htmlunit.WebClient;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
||||
import com.github.mustachejava.DefaultMustacheFactory;
|
||||
import com.github.mustachejava.Mustache;
|
||||
import com.github.mustachejava.MustacheFactory;
|
||||
@@ -71,6 +63,10 @@ public class S101Configurer {
|
||||
|
||||
private final Path licenseDirectory;
|
||||
|
||||
private final String repository;
|
||||
|
||||
private final String version;
|
||||
|
||||
private final Project project;
|
||||
private final Logger logger;
|
||||
|
||||
@@ -90,6 +86,9 @@ public class S101Configurer {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
this.licenseDirectory = new File(System.getProperty("user.home") + "/.Structure101/java").toPath();
|
||||
S101PluginExtension extension = project.getExtensions().getByType(S101PluginExtension.class);
|
||||
this.repository = extension.getRepository().get();
|
||||
this.version = extension.getVersion().get();
|
||||
}
|
||||
|
||||
public void license(String licenseId) {
|
||||
@@ -129,25 +128,7 @@ public class S101Configurer {
|
||||
|
||||
public void configure(File installationDirectory, File configurationDirectory) {
|
||||
deleteDirectory(configurationDirectory);
|
||||
String version = computeVersionFromInstallation(installationDirectory);
|
||||
configureProject(version, configurationDirectory);
|
||||
}
|
||||
|
||||
private String computeVersionFromInstallation(File installationDirectory) {
|
||||
File buildJar = new File(installationDirectory, "structure101-java-build.jar");
|
||||
try (JarInputStream input = new JarInputStream(new FileInputStream(buildJar))) {
|
||||
JarEntry entry;
|
||||
while ((entry = input.getNextJarEntry()) != null) {
|
||||
if (entry.getName().contains("structure101-build.properties")) {
|
||||
Properties properties = new Properties();
|
||||
properties.load(input);
|
||||
return properties.getProperty("s101-build");
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
throw new IllegalStateException("Unable to determine Structure101 version");
|
||||
configureProject(this.version, configurationDirectory);
|
||||
}
|
||||
|
||||
private boolean deleteDirectory(File directoryToBeDeleted) {
|
||||
@@ -161,24 +142,8 @@ public class S101Configurer {
|
||||
}
|
||||
|
||||
private String installBuildTool(File installationDirectory, File configurationDirectory) {
|
||||
String source = "https://structure101.com/binaries/v6";
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
HtmlPage page = webClient.getPage(source);
|
||||
Matcher matcher = null;
|
||||
for (HtmlAnchor anchor : page.getAnchors()) {
|
||||
Matcher candidate = Pattern.compile("(structure101-build-java-all-)(.*).zip").matcher(anchor.getHrefAttribute());
|
||||
if (candidate.find()) {
|
||||
matcher = candidate;
|
||||
}
|
||||
}
|
||||
if (matcher == null) {
|
||||
return null;
|
||||
}
|
||||
copyZipToFilesystem(source, installationDirectory, matcher.group(1) + matcher.group(2));
|
||||
return matcher.group(2);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
copyZipToFilesystem(this.repository, installationDirectory, "structure101-build-java-all-" + this.version);
|
||||
return this.version;
|
||||
}
|
||||
|
||||
private void copyZipToFilesystem(String source, File destination, String name) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,12 @@
|
||||
package s101;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.gargoylesoftware.htmlunit.WebClient;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.Input;
|
||||
@@ -25,6 +30,11 @@ import org.gradle.api.tasks.InputDirectory;
|
||||
|
||||
public class S101PluginExtension {
|
||||
private final Property<String> licenseId;
|
||||
|
||||
private final Property<String> repository;
|
||||
|
||||
private final Property<String> version;
|
||||
|
||||
private final Property<File> installationDirectory;
|
||||
private final Property<File> configurationDirectory;
|
||||
private final Property<String> label;
|
||||
@@ -65,6 +75,24 @@ public class S101PluginExtension {
|
||||
this.label.set(label);
|
||||
}
|
||||
|
||||
@Input
|
||||
public Property<String> getRepository() {
|
||||
return repository;
|
||||
}
|
||||
|
||||
public void setRepository(String repository) {
|
||||
this.repository.set(repository);
|
||||
}
|
||||
|
||||
@Input
|
||||
public Property<String> getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version.set(version);
|
||||
}
|
||||
|
||||
public S101PluginExtension(Project project) {
|
||||
this.licenseId = project.getObjects().property(String.class);
|
||||
if (project.hasProperty("s101.licenseId")) {
|
||||
@@ -78,5 +106,31 @@ public class S101PluginExtension {
|
||||
if (project.hasProperty("s101.label")) {
|
||||
setLabel((String) project.findProperty("s101.label"));
|
||||
}
|
||||
this.repository = project.getObjects().property(String.class);
|
||||
if (project.hasProperty("s101.repository")) {
|
||||
setRepository((String) project.findProperty("s101.repository"));
|
||||
} else {
|
||||
setRepository("https://structure101.com/binaries/v6");
|
||||
}
|
||||
this.version = project.getObjects().property(String.class);
|
||||
if (project.hasProperty("s101.version")) {
|
||||
setVersion((String) project.findProperty("s101.version"));
|
||||
} else {
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
HtmlPage page = webClient.getPage(getRepository().get());
|
||||
Matcher matcher = null;
|
||||
for (HtmlAnchor anchor : page.getAnchors()) {
|
||||
Matcher candidate = Pattern.compile("(structure101-build-java-all-)(.*).zip").matcher(anchor.getHrefAttribute());
|
||||
if (candidate.find()) {
|
||||
matcher = candidate;
|
||||
}
|
||||
}
|
||||
if (matcher != null) {
|
||||
setVersion(matcher.group(2));
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -335,7 +335,6 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
LogoutFilter result = new LogoutFilter(getLogoutSuccessHandler(), handlers);
|
||||
result.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||
result.setLogoutRequestMatcher(getLogoutRequestMatcher(http));
|
||||
result.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||
result = postProcess(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,7 +42,7 @@ public class JdbcUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
String dataSource = element.getAttribute(ATT_DATA_SOURCE);
|
||||
if (dataSource != null) {
|
||||
if (StringUtils.hasText(dataSource)) {
|
||||
builder.addPropertyReference("dataSource", dataSource);
|
||||
}
|
||||
else {
|
||||
|
||||
+37
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,7 +19,10 @@ package org.springframework.security.config.authentication;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.CachingUserDetailsService;
|
||||
import org.springframework.security.authentication.ProviderManager;
|
||||
@@ -33,6 +36,7 @@ import org.springframework.security.provisioning.JdbcUserDetailsManager;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
@@ -160,6 +164,38 @@ public class JdbcUserServiceBeanDefinitionParserTests {
|
||||
assertThat(AuthorityUtils.authorityListToSet(rod.getAuthorities())).contains("PREFIX_ROLE_SUPERVISOR");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyDataSourceRef() {
|
||||
// @formatter:off
|
||||
String xml = "<authentication-manager>"
|
||||
+ " <authentication-provider>"
|
||||
+ " <jdbc-user-service data-source-ref=''/>"
|
||||
+ " </authentication-provider>"
|
||||
+ "</authentication-manager>";
|
||||
assertThatExceptionOfType(BeanDefinitionParsingException.class)
|
||||
.isThrownBy(() -> setContext(xml))
|
||||
.withFailMessage("Expected exception due to empty data-source-ref")
|
||||
.withMessageContaining("data-source-ref is required for jdbc-user-service");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingDataSourceRef() {
|
||||
// @formatter:off
|
||||
String xml = "<authentication-manager>"
|
||||
+ " <authentication-provider>"
|
||||
+ " <jdbc-user-service/>"
|
||||
+ " </authentication-provider>"
|
||||
+ "</authentication-manager>";
|
||||
assertThatExceptionOfType(XmlBeanDefinitionStoreException.class)
|
||||
.isThrownBy(() -> setContext(xml))
|
||||
.withFailMessage("Expected exception due to missing data-source-ref")
|
||||
.havingRootCause()
|
||||
.isInstanceOf(SAXParseException.class)
|
||||
.withMessageContaining("Attribute 'data-source-ref' must appear on element 'jdbc-user-service'");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
this.appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ public class AuthenticatedVoter implements AccessDecisionVoter<Object> {
|
||||
private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
|
||||
|
||||
private boolean isFullyAuthenticated(Authentication authentication) {
|
||||
return (!this.authenticationTrustResolver.isAnonymous(authentication)
|
||||
return authentication != null && (!this.authenticationTrustResolver.isAnonymous(authentication)
|
||||
&& !this.authenticationTrustResolver.isRememberMe(authentication));
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@ public final class AuthorizationManagerAfterMethodInterceptor
|
||||
PostAuthorizeAuthorizationManager authorizationManager) {
|
||||
AuthorizationManagerAfterMethodInterceptor interceptor = new AuthorizationManagerAfterMethodInterceptor(
|
||||
AuthorizationMethodPointcuts.forAnnotations(PostAuthorize.class), authorizationManager);
|
||||
interceptor.setOrder(500);
|
||||
interceptor.setOrder(AuthorizationInterceptorsOrder.POST_AUTHORIZE.getOrder());
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -59,6 +59,7 @@ public class AuthenticatedVoterTests {
|
||||
assertThat(AccessDecisionVoter.ACCESS_GRANTED).isEqualTo(voter.vote(createAnonymous(), null, def));
|
||||
assertThat(AccessDecisionVoter.ACCESS_GRANTED).isEqualTo(voter.vote(createRememberMe(), null, def));
|
||||
assertThat(AccessDecisionVoter.ACCESS_GRANTED).isEqualTo(voter.vote(createFullyAuthenticated(), null, def));
|
||||
assertThat(AccessDecisionVoter.ACCESS_DENIED).isEqualTo(voter.vote(null, null, def));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -68,6 +69,7 @@ public class AuthenticatedVoterTests {
|
||||
assertThat(AccessDecisionVoter.ACCESS_DENIED).isEqualTo(voter.vote(createAnonymous(), null, def));
|
||||
assertThat(AccessDecisionVoter.ACCESS_DENIED).isEqualTo(voter.vote(createRememberMe(), null, def));
|
||||
assertThat(AccessDecisionVoter.ACCESS_GRANTED).isEqualTo(voter.vote(createFullyAuthenticated(), null, def));
|
||||
assertThat(AccessDecisionVoter.ACCESS_DENIED).isEqualTo(voter.vote(null, null, def));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -77,6 +79,7 @@ public class AuthenticatedVoterTests {
|
||||
assertThat(AccessDecisionVoter.ACCESS_DENIED).isEqualTo(voter.vote(createAnonymous(), null, def));
|
||||
assertThat(AccessDecisionVoter.ACCESS_GRANTED).isEqualTo(voter.vote(createRememberMe(), null, def));
|
||||
assertThat(AccessDecisionVoter.ACCESS_GRANTED).isEqualTo(voter.vote(createFullyAuthenticated(), null, def));
|
||||
assertThat(AccessDecisionVoter.ACCESS_DENIED).isEqualTo(voter.vote(null, null, def));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -20,7 +20,7 @@ Java::
|
||||
@Bean
|
||||
SecurityWebFilterChain http(ServerHttpSecurity http) throws Exception {
|
||||
DelegatingServerLogoutHandler logoutHandler = new DelegatingServerLogoutHandler(
|
||||
new WebSessionServerLogoutHandler(), new SecurityContextServerLogoutHandler()
|
||||
new SecurityContextServerLogoutHandler(), new WebSessionServerLogoutHandler()
|
||||
);
|
||||
|
||||
http
|
||||
@@ -38,7 +38,7 @@ Kotlin::
|
||||
@Bean
|
||||
fun http(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||
val customLogoutHandler = DelegatingServerLogoutHandler(
|
||||
WebSessionServerLogoutHandler(), SecurityContextServerLogoutHandler()
|
||||
SecurityContextServerLogoutHandler(), WebSessionServerLogoutHandler()
|
||||
)
|
||||
|
||||
return http {
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
springBootVersion=2.7.12
|
||||
version=5.8.10-SNAPSHOT
|
||||
version=5.8.12
|
||||
samplesBranch=5.8.x
|
||||
org.gradle.jvmargs=-Xmx3g -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError
|
||||
org.gradle.parallel=true
|
||||
|
||||
@@ -15,7 +15,7 @@ org-mockito = "4.8.1"
|
||||
org-opensaml4 = "4.1.0"
|
||||
org-opensaml3 = "3.4.6"
|
||||
org-slf4j = "1.7.36"
|
||||
org-springframework = "5.3.32"
|
||||
org-springframework = "5.3.34"
|
||||
|
||||
[libraries]
|
||||
ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.2.13"
|
||||
@@ -30,8 +30,8 @@ com-unboundid-unboundid-ldapsdk = "com.unboundid:unboundid-ldapsdk:4.0.14"
|
||||
commons-collections = "commons-collections:commons-collections:3.2.2"
|
||||
io-freefair-gradle-aspectj-plugin = "io.freefair.gradle:aspectj-plugin:6.5.1"
|
||||
io-mockk = "io.mockk:mockk:1.13.3"
|
||||
io-projectreactor-netty-reactor-netty = "io.projectreactor.netty:reactor-netty:1.0.41"
|
||||
io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2020.0.41"
|
||||
io-projectreactor-netty-reactor-netty = "io.projectreactor.netty:reactor-netty:1.0.44"
|
||||
io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2020.0.43"
|
||||
io-projectreactor-tools-blockhound = "io.projectreactor.tools:blockhound:1.0.8.RELEASE"
|
||||
io-r2dbc-r2dbc-h2 = { module = "io.r2dbc:r2dbc-h2", version.ref = "io-r2dbc" }
|
||||
io-r2dbc-r2dbc-spi-test = { module = "io.r2dbc:r2dbc-spi-test", version.ref = "io-r2dbc" }
|
||||
|
||||
+10
-8
@@ -22,6 +22,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -179,16 +180,17 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
||||
}
|
||||
|
||||
private OAuth2AuthenticatedPrincipal convertClaimsSet(Map<String, Object> claims) {
|
||||
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> {
|
||||
Map<String, Object> converted = new LinkedHashMap<>(claims);
|
||||
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> {
|
||||
if (v instanceof String) {
|
||||
return Collections.singletonList(v);
|
||||
}
|
||||
return v;
|
||||
});
|
||||
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.CLIENT_ID, (k, v) -> v.toString());
|
||||
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.EXP,
|
||||
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.CLIENT_ID, (k, v) -> v.toString());
|
||||
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.EXP,
|
||||
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
|
||||
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.IAT,
|
||||
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.IAT,
|
||||
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
|
||||
// RFC-7662 page 7 directs users to RFC-7519 for defining the values of these
|
||||
// issuer fields.
|
||||
@@ -208,11 +210,11 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
||||
// may be awkward to debug, we do not want to manipulate this value. Previous
|
||||
// versions of Spring Security
|
||||
// would *only* allow valid URLs, which is not what we wish to achieve here.
|
||||
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString());
|
||||
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF,
|
||||
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString());
|
||||
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF,
|
||||
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
|
||||
Collection<GrantedAuthority> authorities = new ArrayList<>();
|
||||
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> {
|
||||
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> {
|
||||
if (v instanceof String) {
|
||||
Collection<String> scopes = Arrays.asList(((String) v).split(" "));
|
||||
for (String scope : scopes) {
|
||||
@@ -222,7 +224,7 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
|
||||
}
|
||||
return v;
|
||||
});
|
||||
return new OAuth2IntrospectionAuthenticatedPrincipal(claims, authorities);
|
||||
return new OAuth2IntrospectionAuthenticatedPrincipal(converted, authorities);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-8
@@ -22,6 +22,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -136,16 +137,17 @@ public class SpringReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
|
||||
}
|
||||
|
||||
private OAuth2AuthenticatedPrincipal convertClaimsSet(Map<String, Object> claims) {
|
||||
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> {
|
||||
Map<String, Object> converted = new LinkedHashMap<>(claims);
|
||||
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> {
|
||||
if (v instanceof String) {
|
||||
return Collections.singletonList(v);
|
||||
}
|
||||
return v;
|
||||
});
|
||||
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.CLIENT_ID, (k, v) -> v.toString());
|
||||
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.EXP,
|
||||
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.CLIENT_ID, (k, v) -> v.toString());
|
||||
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.EXP,
|
||||
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
|
||||
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.IAT,
|
||||
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.IAT,
|
||||
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
|
||||
// RFC-7662 page 7 directs users to RFC-7519 for defining the values of these
|
||||
// issuer fields.
|
||||
@@ -165,11 +167,11 @@ public class SpringReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
|
||||
// may be awkward to debug, we do not want to manipulate this value. Previous
|
||||
// versions of Spring Security
|
||||
// would *only* allow valid URLs, which is not what we wish to achieve here.
|
||||
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString());
|
||||
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF,
|
||||
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString());
|
||||
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF,
|
||||
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
|
||||
Collection<GrantedAuthority> authorities = new ArrayList<>();
|
||||
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> {
|
||||
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> {
|
||||
if (v instanceof String) {
|
||||
Collection<String> scopes = Arrays.asList(((String) v).split(" "));
|
||||
for (String scope : scopes) {
|
||||
@@ -179,7 +181,7 @@ public class SpringReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
|
||||
}
|
||||
return v;
|
||||
});
|
||||
return new OAuth2IntrospectionAuthenticatedPrincipal(claims, authorities);
|
||||
return new OAuth2IntrospectionAuthenticatedPrincipal(converted, authorities);
|
||||
}
|
||||
|
||||
private OAuth2IntrospectionException onError(Throwable ex) {
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ pluginManagement {
|
||||
|
||||
plugins {
|
||||
id "com.gradle.enterprise" version "3.11.4"
|
||||
id "io.spring.ge.conventions" version "0.0.15"
|
||||
id "io.spring.ge.conventions" version "0.0.16"
|
||||
}
|
||||
|
||||
dependencyResolutionManagement {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -130,9 +130,13 @@ public class StrictHttpFirewall implements HttpFirewall {
|
||||
private static final Predicate<String> ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE = (
|
||||
s) -> ASSIGNED_AND_NOT_ISO_CONTROL_PATTERN.matcher(s).matches();
|
||||
|
||||
private static final Pattern HEADER_VALUE_PATTERN = Pattern.compile("[\\p{IsAssigned}&&[[^\\p{IsControl}]||\\t]]*");
|
||||
|
||||
private static final Predicate<String> HEADER_VALUE_PREDICATE = (s) -> HEADER_VALUE_PATTERN.matcher(s).matches();
|
||||
|
||||
private Predicate<String> allowedHeaderNames = ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE;
|
||||
|
||||
private Predicate<String> allowedHeaderValues = ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE;
|
||||
private Predicate<String> allowedHeaderValues = HEADER_VALUE_PREDICATE;
|
||||
|
||||
private Predicate<String> allowedParameterNames = ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE;
|
||||
|
||||
|
||||
+8
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -782,6 +782,13 @@ public class StrictHttpFirewallTests {
|
||||
assertThatExceptionOfType(RequestRejectedException.class).isThrownBy(() -> request.getHeader("Something"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFirewalledRequestGetHeaderWhenHorizontalTabInHeaderValueThenNoException() {
|
||||
this.request.addHeader("Something", "tab\tvalue");
|
||||
HttpServletRequest request = this.firewall.getFirewalledRequest(this.request);
|
||||
assertThat(request.getHeader("Something")).isEqualTo("tab\tvalue");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFirewalledRequestGetHeaderWhenUndefinedCharacterInHeaderValueThenException() {
|
||||
this.request.addHeader("Something", "bad\uFFFEvalue");
|
||||
|
||||
Reference in New Issue
Block a user