Skip to content

Commit

Permalink
Merge branch 'develop' into feature/alias-id-and-alias-zid-for-identi…
Browse files Browse the repository at this point in the history
…ty-providers
  • Loading branch information
adrianhoelzl-sap committed Feb 8, 2024
2 parents e5f5791 + c011141 commit 8919c63
Show file tree
Hide file tree
Showing 44 changed files with 794 additions and 384 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@ List of relations
public | schema_version | table | root
public | sec_audit | table | root
public | sec_audit_id_seq | sequence | root
public | service_provider | table | root
public | spring_session | table | root
public | spring_session_attributes | table | root
public | user_google_mfa_credentials | table | root
Expand Down
14 changes: 7 additions & 7 deletions dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ ext {
// Versions shared between multiple dependencies
versions.aspectJVersion = "1.9.4"
versions.apacheDsVersion = "2.0.0.AM27"
versions.bouncyCastleVersion = "1.77"
versions.bouncyCastleVersion = "1.0.2.4"
versions.hamcrestVersion = "2.2"
versions.springBootVersion = "2.7.18"
versions.springFrameworkVersion = "5.3.31"
Expand Down Expand Up @@ -40,11 +40,11 @@ libraries.apacheCommonsRngCore = "org.apache.commons:commons-rng-core:1.5"
libraries.apacheCommonsRngSimple = "org.apache.commons:commons-rng-simple:1.5"
libraries.apacheCommonsText = "org.apache.commons:commons-text:1.11.0"
libraries.apacheDsProtocolLdap = "org.apache.directory.server:apacheds-protocol-ldap:${versions.apacheDsVersion}"
libraries.apacheLdapApi = "org.apache.directory.api:api-ldap-model:2.1.5"
libraries.apacheLdapApi = "org.apache.directory.api:api-ldap-model:2.1.6"
libraries.aspectJRt = "org.aspectj:aspectjrt"
libraries.aspectJWeaver = "org.aspectj:aspectjweaver"
libraries.bouncyCastlePkix = "org.bouncycastle:bcpkix-jdk18on:${versions.bouncyCastleVersion}"
libraries.bouncyCastleProv = "org.bouncycastle:bcprov-jdk18on:${versions.bouncyCastleVersion}"
libraries.bouncyCastlePkix = "org.bouncycastle:bcpkix-fips:1.0.7"
libraries.bouncyCastleProv = "org.bouncycastle:bc-fips:${versions.bouncyCastleVersion}"
libraries.braveInstrumentationSpringWebmvc = "io.zipkin.brave:brave-instrumentation-spring-webmvc:${versions.braveVersion}"
libraries.braveContextSlf4j = "io.zipkin.brave:brave-context-slf4j:${versions.braveVersion}"
libraries.commonsIo = "commons-io:commons-io:2.15.1"
Expand Down Expand Up @@ -126,12 +126,12 @@ libraries.unboundIdLdapSdk = "com.unboundid:unboundid-ldapsdk"
libraries.unboundIdScimSdk = "com.unboundid.product.scim:scim-sdk:1.8.26"
libraries.velocity = "org.apache.velocity:velocity-engine-core:2.3"
libraries.xerces = "xerces:xercesImpl:2.12.2"
libraries.zxing = "com.google.zxing:javase:3.5.2"
libraries.zxing = "com.google.zxing:javase:3.5.3"
libraries.nimbusJwt = "com.nimbusds:nimbus-jose-jwt:9.37.3"
libraries.xmlSecurity = "org.apache.santuario:xmlsec:4.0.1"
libraries.orgJson = "org.json:json:20231013"
libraries.orgJson = "org.json:json:20240205"
libraries.owaspEsapi = "org.owasp.esapi:esapi:2.5.3.1"
libraries.jodaTime = "joda-time:joda-time:2.12.6"
libraries.jodaTime = "joda-time:joda-time:2.12.7"
libraries.commonsHttpClient = "commons-httpclient:commons-httpclient:3.1"

// gradle plugins
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
20 changes: 10 additions & 10 deletions gradlew.bat
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2

goto fail

Expand All @@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto execute

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2

goto fail

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.cloudfoundry.identity.uaa.util;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
Expand Down Expand Up @@ -55,6 +56,15 @@ public static <T> T readValue(String s, Class<T> clazz) throws JsonUtilException
}
}

public static Map<String, Object> readValueAsMap(final String input) {
try {
final JsonNode rootNode = objectMapper.readTree(input);
return getNodeAsMap(rootNode);
} catch (final JsonProcessingException e) {
throw new JsonUtilException(e);
}
}

public static <T> T readValue(byte[] data, Class<T> clazz) throws JsonUtilException {
try {
if (data!=null && data.length>0) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package org.cloudfoundry.identity.uaa.util;

import com.fasterxml.jackson.core.type.TypeReference;

import org.assertj.core.api.Assertions;
import org.cloudfoundry.identity.uaa.metrics.UrlGroup;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
Expand Down Expand Up @@ -42,6 +47,26 @@ void testReadValueByteClass() {
assertNull(JsonUtils.readValue((byte[]) null, UrlGroup.class));
}

@Test
void testReadValueAsMap() {
final String jsonInput = "{\"prop1\":\"abc\",\"prop2\":{\"prop2a\":\"def\",\"prop2b\":\"ghi\"},\"prop3\":[\"jkl\",\"mno\"]}";
final Map<String, Object> map = JsonUtils.readValueAsMap(jsonInput);
Assertions.assertThat(map).isNotNull();
Assertions.assertThat(map.get("prop1")).isNotNull().isEqualTo("abc");
Assertions.assertThat(map.get("prop2")).isNotNull().isInstanceOf(Map.class);
Assertions.assertThat(((Map<String, Object>) map.get("prop2")).get("prop2a")).isNotNull().isEqualTo("def");
Assertions.assertThat(((Map<String, Object>) map.get("prop2")).get("prop2b")).isNotNull().isEqualTo("ghi");
Assertions.assertThat(map.get("prop3")).isNotNull().isInstanceOf(List.class);
Assertions.assertThat((List<String>) map.get("prop3")).containsExactly("jkl", "mno");
}

@ParameterizedTest
@ValueSource(strings = {"{", "}", "{\"prop1\":\"abc\","})
void testReadValueAsMap_Invalid(final String input) {
Assertions.assertThatExceptionOfType(JsonUtils.JsonUtilException.class)
.isThrownBy(() -> JsonUtils.readValueAsMap(input));
}

@Test
void testReadValueBytes() {
assertNotNull(JsonUtils.readValue(jsonTestObjectString.getBytes(), new TypeReference<Map<String, Object>>() {}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,27 @@
*******************************************************************************/
package org.cloudfoundry.identity.uaa.scim;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import static java.util.Optional.ofNullable;
import static org.springframework.util.StringUtils.hasText;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import org.cloudfoundry.identity.uaa.approval.Approval;
import org.cloudfoundry.identity.uaa.impl.JsonDateSerializer;
import org.cloudfoundry.identity.uaa.scim.impl.ScimUserJsonDeserializer;
import org.springframework.util.Assert;

import java.util.*;

import static java.util.Optional.ofNullable;
import static org.springframework.util.StringUtils.hasText;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

/**
* Object to hold SCIM data for Jackson to map to and from JSON
Expand Down Expand Up @@ -772,6 +779,10 @@ public void patch(ScimUser patch) {
}
}

if (hasText(patch.getOrigin()) && !patch.getOrigin().equals(getOrigin())) {
throw new IllegalArgumentException("Cannot change origin in patch of user.");
}

//Merge simple Attributes, that are stored
ofNullable(patch.getUserName()).ifPresent(this::setUserName);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,13 @@ public class UserConfig {

private List<String> defaultGroups = DEFAULT_ZONE_GROUPS;

// in addition to defaultGroups, which are implicitely allowed
private List<String> allowedGroups = null;

private int maxUsers = -1;

private boolean checkOriginEnabled;

public List<String> getDefaultGroups() {
return defaultGroups;
}
Expand All @@ -32,9 +37,6 @@ public void setDefaultGroups(List<String> defaultGroups) {
this.defaultGroups = defaultGroups;
}

// in addition to defaultGroups, which are implicitely allowed
private List<String> allowedGroups = null;

public List<String> getAllowedGroups() {
return allowedGroups;
}
Expand Down Expand Up @@ -65,4 +67,12 @@ public int getMaxUsers() {
public void setMaxUsers(int maxUsers) {
this.maxUsers = maxUsers;
}

public boolean isCheckOriginEnabled() {
return this.checkOriginEnabled;
}

public void setCheckOriginEnabled(boolean checkOriginEnabled) {
this.checkOriginEnabled = checkOriginEnabled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,5 +139,6 @@ void deserialize() {
"scim.me", "cloud_controller.user"),
sampleIdentityZone.getConfig().getUserConfig().resultingAllowedGroups());
assertEquals(1000, sampleIdentityZone.getConfig().getUserConfig().getMaxUsers());
assertEquals(true, sampleIdentityZone.getConfig().getUserConfig().isCheckOriginEnabled());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@
"scim.me",
"cloud_controller.user"
],
"maxUsers": 1000
"maxUsers": 1000,
"checkOriginEnabled": true
}
},
"name": "Demo Login Page",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import org.cloudfoundry.identity.uaa.codestore.ExpiringCode;
import org.cloudfoundry.identity.uaa.codestore.ExpiringCodeStore;
import org.cloudfoundry.identity.uaa.constants.OriginKeys;
import org.cloudfoundry.identity.uaa.login.PasscodeInformation;
import org.cloudfoundry.identity.uaa.passcode.PasscodeInformation;
import org.cloudfoundry.identity.uaa.user.UaaUser;
import org.cloudfoundry.identity.uaa.user.UaaUserDatabase;
import org.cloudfoundry.identity.uaa.util.JsonUtils;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package org.cloudfoundry.identity.uaa.cypto;

import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.PasswordBasedDeriver;
import org.bouncycastle.crypto.PasswordConverter;
import org.bouncycastle.crypto.fips.FipsPBKD;
import org.bouncycastle.crypto.fips.FipsSHS;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
import org.bouncycastle.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -12,8 +14,6 @@
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;

public class EncryptionService {
Expand All @@ -40,7 +40,7 @@ public byte[] encrypt(String plaintext) throws EncryptionServiceException {

SecretKey key = new SecretKeySpec(generateKey(newSalt), CIPHER);

Cipher myCipher = Cipher.getInstance(CIPHERSCHEME);
Cipher myCipher = Cipher.getInstance(CIPHERSCHEME, BouncyCastleFipsProvider.PROVIDER_NAME);
byte[] newNonce = generateRandomArray(GCM_IV_NONCE_SIZE_BYTES);

GCMParameterSpec spec = new GCMParameterSpec(GCM_AUTHENTICATION_TAG_SIZE_BITS, newNonce);
Expand Down Expand Up @@ -84,9 +84,12 @@ private byte[] generateRandomArray(int sizeInBytes) {
}

private byte[] generateKey(byte[] salt) {
PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA256Digest());

gen.init(this.passphrase.getBytes(StandardCharsets.UTF_8), salt, PBKDF2_ITERATIONS);
return ((KeyParameter) gen.generateDerivedParameters(AES_KEY_LENGTH_BITS)).getKey();
PasswordBasedDeriver<FipsPBKD.Parameters> gen = new FipsPBKD.DeriverFactory().createDeriver(
FipsPBKD.PBKDF2.using(FipsSHS.Algorithm.SHA256_HMAC,
PasswordConverter.UTF8.convert(this.passphrase.toCharArray()))
.withIterationCount(PBKDF2_ITERATIONS)
.withSalt(salt)
);
return gen.deriveKey(PasswordBasedDeriver.KeyType.CIPHER, (AES_KEY_LENGTH_BITS + 7) / 8);
}
}
Loading

0 comments on commit 8919c63

Please sign in to comment.