Skip to content

Commit

Permalink
Merge
Browse files Browse the repository at this point in the history
  • Loading branch information
strehle committed Aug 24, 2023
2 parents 127d570 + bf6f7b2 commit e4ea431
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -1,23 +1,76 @@
package org.cloudfoundry.identity.uaa.client;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;

import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@JsonInclude(JsonInclude.Include.NON_DEFAULT)
@JsonIgnoreProperties(ignoreUnknown = true)
public class UaaClientDetails extends BaseClientDetails {

private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

@JsonProperty("client_jwt_config")
private String clientJwtConfig;

public UaaClientDetails() {
}

UaaClientDetails(ClientDetails prototype) {
super(prototype);
this.setAdditionalInformation(prototype.getAdditionalInformation());
}

public UaaClientDetails(String clientId, String resourceIds,
String scopes, String grantTypes, String authorities, String redirectUris) {
super(clientId, resourceIds, scopes, grantTypes, authorities, redirectUris);
}

@Override
public void setScope(Collection<String> scope) {
Set<String> sanitized = scope.stream()
.flatMap(s -> Arrays.stream(s.split(",")))
.collect(Collectors.toSet());
super.setScope(sanitized);
}

public String getClientJwtConfig() {
return clientJwtConfig;
}

public void setClientJwtConfig(String clientJwtConfig) {
this.clientJwtConfig = clientJwtConfig;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (o instanceof UaaClientDetails) {
UaaClientDetails uaaClientDetails = (UaaClientDetails) o;
return Objects.equals(clientJwtConfig, uaaClientDetails.clientJwtConfig);
}
return false;
}

@Override
public int hashCode() {
int result = super.hashCode();

result = 31 * result + (clientJwtConfig != null ? clientJwtConfig.hashCode() : 0);
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.NoSuchClientException;

Expand All @@ -25,9 +24,9 @@ public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
}

public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
ClientDetails clientDetails;
UaaClientDetails clientDetails;
try {
clientDetails = clientDetailsService.loadClientByClientId(username);
clientDetails = (UaaClientDetails) clientDetailsService.loadClientByClientId(username);
} catch (NoSuchClientException e) {
throw new UsernameNotFoundException(e.getMessage(), e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.cloudfoundry.identity.uaa.zone;

import org.cloudfoundry.identity.uaa.client.UaaClientDetails;
import org.cloudfoundry.identity.uaa.zone.beans.IdentityZoneManager;
import org.springframework.security.oauth2.provider.*;

Expand All @@ -11,8 +12,12 @@ interface MultitenantClientRegistrationService extends ClientRegistrationService

void updateClientDetails(ClientDetails clientDetails, String zoneId) throws NoSuchClientException;

void addUaaClientDetails(UaaClientDetails uaaClientDetails, String zoneId) throws ClientAlreadyExistsException;

void updateClientSecret(String clientId, String secret, String zoneId) throws NoSuchClientException;

void updateClientJwtConfig(String clientId, String keyConfig, String zoneId) throws NoSuchClientException;

void removeClientDetails(String clientId, String zoneId) throws NoSuchClientException;

List<ClientDetails> listClientDetails(String zoneId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.cloudfoundry.identity.uaa.audit.event.SystemDeletable;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
import org.cloudfoundry.identity.uaa.client.UaaClientDetails;
import org.cloudfoundry.identity.uaa.client.ClientJwtConfiguration;
import org.cloudfoundry.identity.uaa.oauth.client.ClientConstants;
import org.cloudfoundry.identity.uaa.resources.ResourceMonitor;
Expand All @@ -27,7 +28,6 @@
import org.springframework.security.oauth2.provider.ClientAlreadyExistsException;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.NoSuchClientException;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
Expand Down Expand Up @@ -66,7 +66,7 @@ public class MultitenantJdbcClientDetailsService extends MultitenantClientServic
"authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, " +
"refresh_token_validity, additional_information, autoapprove, lastmodified, required_user_groups";

private static final String CLIENT_FIELDS = "client_secret, " + CLIENT_FIELDS_FOR_UPDATE;
private static final String CLIENT_FIELDS = "client_secret, client_jwt_config, " + CLIENT_FIELDS_FOR_UPDATE;

private static final String BASE_FIND_STATEMENT =
"select client_id, " + CLIENT_FIELDS + " from oauth_client_details";
Expand All @@ -82,7 +82,7 @@ public class MultitenantJdbcClientDetailsService extends MultitenantClientServic

private static final String DEFAULT_INSERT_STATEMENT =
"insert into oauth_client_details (" + CLIENT_FIELDS
+ ", client_id, identity_zone_id, created_by) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
+ ", client_id, identity_zone_id, created_by) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";

private static final String DEFAULT_UPDATE_STATEMENT =
"update oauth_client_details " + "set "
Expand All @@ -92,6 +92,10 @@ public class MultitenantJdbcClientDetailsService extends MultitenantClientServic
"update oauth_client_details "
+ "set client_secret = ? where client_id = ? and identity_zone_id = ?";

private static final String DEFAULT_UPDATE_CLIENT_JWT_CONFIG_STATEMENT =
"update oauth_client_details "
+ "set client_jwt_config = ? where client_id = ? and identity_zone_id = ?";

static final String DEFAULT_DELETE_STATEMENT =
"delete from oauth_client_details where client_id = ? and identity_zone_id = ?";

Expand Down Expand Up @@ -155,6 +159,14 @@ public void updateClientDetails(ClientDetails clientDetails, String zoneId) thro
}
}

@Override
public void addUaaClientDetails(UaaClientDetails uaaClientDetails, String zoneId) throws ClientAlreadyExistsException {
if (exists(uaaClientDetails.getClientId(), zoneId)) {
throw new ClientAlreadyExistsException("Client already exists: " + uaaClientDetails.getClientId());
}
jdbcTemplate.update(DEFAULT_INSERT_STATEMENT, getInsertClientDetailsFields(uaaClientDetails, zoneId));
}

@Override
public void updateClientSecret(String clientId, String secret, String zoneId) throws NoSuchClientException {
int count = jdbcTemplate.update(DEFAULT_UPDATE_SECRET_STATEMENT, passwordEncoder.encode(secret), clientId, zoneId);
Expand All @@ -163,6 +175,14 @@ public void updateClientSecret(String clientId, String secret, String zoneId) th
}
}

@Override
public void updateClientJwtConfig(String clientId, String keyConfig, String zoneId) throws NoSuchClientException {
int count = jdbcTemplate.update(DEFAULT_UPDATE_CLIENT_JWT_CONFIG_STATEMENT, keyConfig, clientId, zoneId);
if (count != 1) {
throw new NoSuchClientException("No client found with id = " + clientId);
}
}

@Override
public void removeClientDetails(String clientId, String zoneId) throws NoSuchClientException {
deleteByClient(clientId, zoneId);
Expand All @@ -174,12 +194,13 @@ public List<ClientDetails> listClientDetails(String zoneId) {

private Object[] getInsertClientDetailsFields(ClientDetails clientDetails, String zoneId) {
Object[] fieldsForUpdate = getFieldsForUpdate(clientDetails, zoneId);
Object[] clientDetailFieldsForUpdate = new Object[fieldsForUpdate.length + 2];
System.arraycopy(fieldsForUpdate, 0, clientDetailFieldsForUpdate, 1, fieldsForUpdate.length);
Object[] clientDetailFieldsForUpdate = new Object[fieldsForUpdate.length + 3];
System.arraycopy(fieldsForUpdate, 0, clientDetailFieldsForUpdate, 2, fieldsForUpdate.length);
clientDetailFieldsForUpdate[0] =
clientDetails.getClientSecret() != null ?
passwordEncoder.encode(clientDetails.getClientSecret()) :
null;
clientDetailFieldsForUpdate[1] = (clientDetails instanceof UaaClientDetails) ? ((UaaClientDetails) clientDetails).getClientJwtConfig() : null;
clientDetailFieldsForUpdate[clientDetailFieldsForUpdate.length - 1] = getUserId();
return clientDetailFieldsForUpdate;
}
Expand Down Expand Up @@ -319,23 +340,24 @@ public void deleteClientJwtConfig(String clientId, String keyConfig, String zone
*/
private static class ClientDetailsRowMapper implements RowMapper<ClientDetails> {
public ClientDetails mapRow(ResultSet rs, int rowNum) throws SQLException {
BaseClientDetails details = new BaseClientDetails(
UaaClientDetails details = new UaaClientDetails(
rs.getString(1),
rs.getString(3),
rs.getString(4),
rs.getString(5),
rs.getString(7),
rs.getString(6)
rs.getString(6),
rs.getString(8),
rs.getString(7)
);
details.setClientSecret(rs.getString(2));
if (rs.getObject(8) != null) {
details.setAccessTokenValiditySeconds(rs.getInt(8));
}
details.setClientJwtConfig(rs.getString(3));
if (rs.getObject(9) != null) {
details.setRefreshTokenValiditySeconds(rs.getInt(9));
details.setAccessTokenValiditySeconds(rs.getInt(9));
}
if (rs.getObject(10) != null) {
details.setRefreshTokenValiditySeconds(rs.getInt(10));
}
String json = rs.getString(10);
String scopes = rs.getString(11);
String json = rs.getString(11);
String scopes = rs.getString(12);
Set<String> autoApproveScopes = new HashSet<>();
if (scopes != null) {
autoApproveScopes = commaDelimitedListToSet(scopes);
Expand Down Expand Up @@ -365,12 +387,12 @@ public ClientDetails mapRow(ResultSet rs, int rowNum) throws SQLException {


// lastModified
if (rs.getObject(12) != null) {
details.addAdditionalInformation("lastModified", rs.getTimestamp(12));
if (rs.getObject(13) != null) {
details.addAdditionalInformation("lastModified", rs.getTimestamp(13));
}

//required_user_groups
String requiredUserGroups = rs.getString(13);
String requiredUserGroups = rs.getString(14);
if (StringUtils.isEmpty(requiredUserGroups)) {
details.addAdditionalInformation(REQUIRED_USER_GROUPS, emptySet());
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE oauth_client_details ADD COLUMN client_jwt_config CLOB DEFAULT NULL;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE oauth_client_details ADD COLUMN client_jwt_config TEXT DEFAULT NULL;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE oauth_client_details ADD COLUMN client_jwt_config TEXT DEFAULT NULL;
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@
import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
import static org.hamcrest.collection.IsMapContaining.hasEntry;
import static org.hamcrest.collection.IsMapWithSize.aMapWithSize;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;

class UaaClientDetailsTest {
@Nested

@Nested
class Creation {
private BaseClientDetails testClient;

Expand Down Expand Up @@ -63,6 +66,35 @@ void copiesAdditionalInformation() {
.withAdditionalInformation(allOf(aMapWithSize(1), hasEntry("key", "value")))
));
}

@Test
void testClientJwtConfig() {
UaaClientDetails copy = new UaaClientDetails(testClient);
copy.setClientJwtConfig("test");
assertEquals("test", copy.getClientJwtConfig());
}

@Test
void testEquals() {
UaaClientDetails copy = new UaaClientDetails(testClient);
UaaClientDetails copy2 = new UaaClientDetails(testClient);
copy.setClientJwtConfig("test");
assertNotEquals(copy, copy2);
assertNotEquals(copy, new UaaClientDetails());
copy.setClientJwtConfig(null);
assertEquals(copy, copy2);
}

@Test
void testHashCode() {
UaaClientDetails copy = new UaaClientDetails(testClient);
UaaClientDetails copy2 = new UaaClientDetails(testClient.getClientId(), "",
"test.none", "", "test.admin", null);
copy.setClientJwtConfig("test");
assertNotEquals(copy.hashCode(), copy2.hashCode());
copy.setClientJwtConfig(null);
assertEquals(copy.hashCode(), copy2.hashCode());
}
}

@Nested
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.cloudfoundry.identity.uaa.zone;

import org.cloudfoundry.identity.uaa.client.UaaClientDetails;
import org.cloudfoundry.identity.uaa.zone.beans.IdentityZoneManager;
import org.springframework.security.oauth2.provider.ClientAlreadyExistsException;
import org.springframework.security.oauth2.provider.ClientDetails;
Expand Down Expand Up @@ -68,13 +69,23 @@ public void updateClientDetails(ClientDetails clientDetails, String zoneId) thro
addClientDetails(clientDetails, zoneId);
}

@Override
public void addUaaClientDetails(UaaClientDetails uaaClientDetails, String zoneId) throws ClientAlreadyExistsException {
getInMemoryService(zoneId).put(uaaClientDetails.getClientId(), (BaseClientDetails) uaaClientDetails);
}

@Override
public void updateClientSecret(String clientId, String secret, String zoneId) throws NoSuchClientException {
ofNullable((BaseClientDetails) loadClientByClientId(clientId, zoneId)).ifPresent(client ->
client.setClientSecret(secret)
);
}

@Override
public void updateClientJwtConfig(String clientId, String keyConfig, String zoneId) throws NoSuchClientException {
throw new UnsupportedOperationException();
}

@Override
public void removeClientDetails(String clientId, String zoneId) throws NoSuchClientException {
getInMemoryService(zoneId).remove(clientId);
Expand Down
Loading

0 comments on commit e4ea431

Please sign in to comment.