mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-28 14:52:24 +00:00
Move OpenSAML 4 Support to Separate Source Directory
Issue gh-11658
This commit is contained in:
parent
1be596bb2f
commit
c6d6bfd74f
@ -1,5 +1,25 @@
|
|||||||
apply plugin: 'io.spring.convention.spring-module'
|
apply plugin: 'io.spring.convention.spring-module'
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
opensaml4Main { extendsFrom(optional, provided) }
|
||||||
|
opensaml4Test { extendsFrom(opensaml4Main, tests) }
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
opensaml4Main {
|
||||||
|
java {
|
||||||
|
compileClasspath += main.output + configurations.opensaml4Main
|
||||||
|
srcDir 'src/opensaml4Main/java'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opensaml4Test {
|
||||||
|
java {
|
||||||
|
compileClasspath += main.output + test.output + opensaml4Main.output + configurations.opensaml4Test
|
||||||
|
srcDir 'src/opensaml4Test/java'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sourceSets.configureEach { set ->
|
sourceSets.configureEach { set ->
|
||||||
if (!set.name.containsIgnoreCase("main")) {
|
if (!set.name.containsIgnoreCase("main")) {
|
||||||
return
|
return
|
||||||
@ -76,3 +96,34 @@ dependencies {
|
|||||||
testImplementation "org.mockito:mockito-junit-jupiter"
|
testImplementation "org.mockito:mockito-junit-jupiter"
|
||||||
testImplementation "org.springframework:spring-test"
|
testImplementation "org.springframework:spring-test"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
|
from sourceSets.opensaml4Main.output
|
||||||
|
}
|
||||||
|
|
||||||
|
sourcesJar {
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
|
from sourceSets.opensaml4Main.allJava
|
||||||
|
}
|
||||||
|
|
||||||
|
testJar {
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
|
from sourceSets.opensaml4Test.output
|
||||||
|
}
|
||||||
|
|
||||||
|
javadoc {
|
||||||
|
classpath += sourceSets.opensaml4Main.runtimeClasspath
|
||||||
|
source += sourceSets.opensaml4Main.allJava
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register("opensaml4Test", Test) {
|
||||||
|
useJUnitPlatform()
|
||||||
|
classpath += sourceSets.opensaml4Test.output
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tasks.named("test") {
|
||||||
|
dependsOn opensaml4Test
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.security.saml2.provider.service.authentication.logout;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.zip.Deflater;
|
||||||
|
import java.util.zip.DeflaterOutputStream;
|
||||||
|
import java.util.zip.Inflater;
|
||||||
|
import java.util.zip.InflaterOutputStream;
|
||||||
|
|
||||||
|
import org.springframework.security.saml2.Saml2Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility methods for working with serialized SAML messages.
|
||||||
|
*
|
||||||
|
* For internal use only.
|
||||||
|
*
|
||||||
|
* @author Josh Cummings
|
||||||
|
*/
|
||||||
|
final class Saml2Utils {
|
||||||
|
|
||||||
|
private Saml2Utils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static String samlEncode(byte[] b) {
|
||||||
|
return Base64.getEncoder().encodeToString(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] samlDecode(String s) {
|
||||||
|
return Base64.getMimeDecoder().decode(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] samlDeflate(String s) {
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
DeflaterOutputStream deflater = new DeflaterOutputStream(b, new Deflater(Deflater.DEFLATED, true));
|
||||||
|
deflater.write(s.getBytes(StandardCharsets.UTF_8));
|
||||||
|
deflater.finish();
|
||||||
|
return b.toByteArray();
|
||||||
|
}
|
||||||
|
catch (IOException ex) {
|
||||||
|
throw new Saml2Exception("Unable to deflate string", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static String samlInflate(byte[] b) {
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
InflaterOutputStream iout = new InflaterOutputStream(out, new Inflater(true));
|
||||||
|
iout.write(b);
|
||||||
|
iout.finish();
|
||||||
|
return new String(out.toByteArray(), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
catch (IOException ex) {
|
||||||
|
throw new Saml2Exception("Unable to inflate string", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static EncodingConfigurer withDecoded(String decoded) {
|
||||||
|
return new EncodingConfigurer(decoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DecodingConfigurer withEncoded(String encoded) {
|
||||||
|
return new DecodingConfigurer(encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class EncodingConfigurer {
|
||||||
|
|
||||||
|
private final String decoded;
|
||||||
|
|
||||||
|
private boolean deflate;
|
||||||
|
|
||||||
|
private EncodingConfigurer(String decoded) {
|
||||||
|
this.decoded = decoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
EncodingConfigurer deflate(boolean deflate) {
|
||||||
|
this.deflate = deflate;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String encode() {
|
||||||
|
byte[] bytes = (this.deflate) ? Saml2Utils.samlDeflate(this.decoded)
|
||||||
|
: this.decoded.getBytes(StandardCharsets.UTF_8);
|
||||||
|
return Saml2Utils.samlEncode(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class DecodingConfigurer {
|
||||||
|
|
||||||
|
private static final Base64Checker BASE_64_CHECKER = new Base64Checker();
|
||||||
|
|
||||||
|
private final String encoded;
|
||||||
|
|
||||||
|
private boolean inflate;
|
||||||
|
|
||||||
|
private boolean requireBase64;
|
||||||
|
|
||||||
|
private DecodingConfigurer(String encoded) {
|
||||||
|
this.encoded = encoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
DecodingConfigurer inflate(boolean inflate) {
|
||||||
|
this.inflate = inflate;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
DecodingConfigurer requireBase64(boolean requireBase64) {
|
||||||
|
this.requireBase64 = requireBase64;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String decode() {
|
||||||
|
if (this.requireBase64) {
|
||||||
|
BASE_64_CHECKER.checkAcceptable(this.encoded);
|
||||||
|
}
|
||||||
|
byte[] bytes = Saml2Utils.samlDecode(this.encoded);
|
||||||
|
return (this.inflate) ? Saml2Utils.samlInflate(bytes) : new String(bytes, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Base64Checker {
|
||||||
|
|
||||||
|
private static final int[] values = genValueMapping();
|
||||||
|
|
||||||
|
Base64Checker() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[] genValueMapping() {
|
||||||
|
byte[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||||
|
.getBytes(StandardCharsets.ISO_8859_1);
|
||||||
|
|
||||||
|
int[] values = new int[256];
|
||||||
|
Arrays.fill(values, -1);
|
||||||
|
for (int i = 0; i < alphabet.length; i++) {
|
||||||
|
values[alphabet[i] & 0xff] = i;
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isAcceptable(String s) {
|
||||||
|
int goodChars = 0;
|
||||||
|
int lastGoodCharVal = -1;
|
||||||
|
|
||||||
|
// count number of characters from Base64 alphabet
|
||||||
|
for (int i = 0; i < s.length(); i++) {
|
||||||
|
int val = values[0xff & s.charAt(i)];
|
||||||
|
if (val != -1) {
|
||||||
|
lastGoodCharVal = val;
|
||||||
|
goodChars++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// in cases of an incomplete final chunk, ensure the unused bits are zero
|
||||||
|
switch (goodChars % 4) {
|
||||||
|
case 0:
|
||||||
|
return true;
|
||||||
|
case 2:
|
||||||
|
return (lastGoodCharVal & 0b1111) == 0;
|
||||||
|
case 3:
|
||||||
|
return (lastGoodCharVal & 0b11) == 0;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkAcceptable(String ins) {
|
||||||
|
if (!isAcceptable(ins)) {
|
||||||
|
throw new IllegalArgumentException("Failed to decode SAMLResponse");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2024 the original author or authors.
|
* Copyright 2002-2021 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2024 the original author or authors.
|
* Copyright 2002-2021 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
Loading…
x
Reference in New Issue
Block a user