Skip to content

Commit

Permalink
Merge branch 'develop' into scope-management
Browse files Browse the repository at this point in the history
  • Loading branch information
enricovianello committed Aug 22, 2022
2 parents 798c905 + 956b4da commit 8d08924
Show file tree
Hide file tree
Showing 57 changed files with 1,162 additions and 172 deletions.
4 changes: 2 additions & 2 deletions iam-common/pom.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
<project xmlns:ns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>it.infn.mw</groupId>
<artifactId>iam-parent</artifactId>
<version>1.8.0.beta.20220422</version>
<version>1.8.0</version>
</parent>

<artifactId>iam-common</artifactId>
Expand Down
6 changes: 3 additions & 3 deletions iam-login-service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
<project xmlns:ns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>it.infn.mw</groupId>
<artifactId>iam-parent</artifactId>
<version>1.8.0.beta.20220422</version>
<version>1.8.0</version>
</parent>

<artifactId>iam-login-service</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.NO_CONTENT;

import java.text.ParseException;
import java.util.Optional;

import javax.servlet.http.HttpServletRequest;
Expand Down Expand Up @@ -68,7 +69,8 @@ public ClientManagementAPIController(ClientManagementService managementService)

@PostMapping
@ResponseStatus(CREATED)
public RegisteredClientDTO saveNewClient(@RequestBody RegisteredClientDTO client) {
public RegisteredClientDTO saveNewClient(@RequestBody RegisteredClientDTO client)
throws ParseException {
return managementService.saveNewClient(client);
}

Expand Down Expand Up @@ -126,7 +128,8 @@ public void removeClientOwner(@PathVariable String clientId,

@PutMapping("/{clientId}")
public RegisteredClientDTO updateClient(@PathVariable String clientId,
@RequestBody RegisteredClientDTO client) {
@RequestBody RegisteredClientDTO client)
throws ParseException {
return managementService.updateClient(clientId, client);
}

Expand Down Expand Up @@ -160,4 +163,9 @@ public ErrorDTO noSuchClient(HttpServletRequest req, Exception ex) {
return ErrorDTO.fromString(ex.getMessage());
}

@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ExceptionHandler(ParseException.class)
public ErrorDTO jsonMappingError(HttpServletRequest req, Exception ex) {
return ErrorDTO.fromString(ex.getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package it.infn.mw.iam.api.client.management.service;

import java.text.ParseException;
import java.util.Optional;

import javax.validation.Valid;
Expand All @@ -37,10 +38,11 @@ ListResponseDTO<RegisteredClientDTO> retrieveAllDynamicallyRegisteredClients(

Optional<RegisteredClientDTO> retrieveClientByClientId(@NotBlank String clientId);

RegisteredClientDTO saveNewClient(@NotNull @Valid RegisteredClientDTO client);
RegisteredClientDTO saveNewClient(@NotNull @Valid RegisteredClientDTO client)
throws ParseException;

RegisteredClientDTO updateClient(@NotBlank String clientId,
@NotNull @Valid RegisteredClientDTO client);
@NotNull @Valid RegisteredClientDTO client) throws ParseException;

RegisteredClientDTO generateNewClientSecret(@NotBlank String clientId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static it.infn.mw.iam.api.client.util.ClientSuppliers.accountNotFound;
import static it.infn.mw.iam.api.client.util.ClientSuppliers.clientNotFound;

import java.text.ParseException;
import java.time.Clock;
import java.util.Date;
import java.util.Optional;
Expand Down Expand Up @@ -110,7 +111,8 @@ public Optional<RegisteredClientDTO> retrieveClientByClientId(String clientId) {

@Validated(OnClientCreation.class)
@Override
public RegisteredClientDTO saveNewClient(RegisteredClientDTO client) {
public RegisteredClientDTO saveNewClient(RegisteredClientDTO client)
throws ParseException {

ClientDetailsEntity entity = converter.entityFromClientManagementRequest(client);
entity.setDynamicallyRegistered(false);
Expand All @@ -134,7 +136,8 @@ public void deleteClientByClientId(String clientId) {

@Validated(OnClientUpdate.class)
@Override
public RegisteredClientDTO updateClient(String clientId, RegisteredClientDTO client) {
public RegisteredClientDTO updateClient(String clientId, RegisteredClientDTO client)
throws ParseException {

ClientDetailsEntity oldClient = clientService.findClientByClientId(clientId)
.orElseThrow(ClientSuppliers.clientNotFound(clientId));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.NO_CONTENT;

import java.text.ParseException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;

Expand Down Expand Up @@ -63,8 +65,8 @@ public ClientRegistrationApiController(ClientRegistrationService service) {
@PostMapping
@ResponseStatus(code = CREATED)
@JsonView({ClientViews.DynamicRegistration.class})
public RegisteredClientDTO registerClient(
@RequestBody RegisteredClientDTO request, Authentication authentication) {
public RegisteredClientDTO registerClient(@RequestBody RegisteredClientDTO request,
Authentication authentication) throws ParseException {
return service.registerClient(request, authentication);

}
Expand All @@ -80,7 +82,8 @@ public RegisteredClientDTO retrieveClient(@PathVariable String clientId,
@PutMapping("/{clientId}")
@JsonView({ClientViews.DynamicRegistration.class})
public RegisteredClientDTO updateClient(@PathVariable String clientId,
@RequestBody RegisteredClientDTO request, Authentication authentication) {
@RequestBody RegisteredClientDTO request, Authentication authentication)
throws ParseException {

return service.updateClient(clientId, request, authentication);
}
Expand All @@ -105,6 +108,12 @@ public ErrorDTO constraintValidationError(HttpServletRequest req, Exception ex)
return ErrorDTO.fromString(ex.getMessage());
}

@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ExceptionHandler(ParseException.class)
public ErrorDTO parseExceptionError(HttpServletRequest req, Exception ex) {
return ErrorDTO.fromString(ex.getMessage());
}

@ResponseStatus(value = HttpStatus.NOT_FOUND)
@ExceptionHandler(NoSuchClient.class)
public ErrorDTO noSuchClient(HttpServletRequest req, Exception ex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package it.infn.mw.iam.api.client.registration.service;

import java.text.ParseException;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;

Expand All @@ -25,14 +27,13 @@
public interface ClientRegistrationService {

RegisteredClientDTO registerClient(@Valid RegisteredClientDTO request,
Authentication authentication);
Authentication authentication) throws ParseException;

RegisteredClientDTO retrieveClient(@NotBlank String clientId,
Authentication authentication);

RegisteredClientDTO updateClient(@NotBlank String clientId,
@Valid RegisteredClientDTO request,
Authentication authentication);
RegisteredClientDTO updateClient(@NotBlank String clientId, @Valid RegisteredClientDTO request,
Authentication authentication) throws ParseException;

void deleteClient(@NotBlank String clientId, Authentication authentication);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ && registrationAccessTokenAuthenticationValidForClientId(client.getClientId(), a
@Validated(OnDynamicClientRegistration.class)
@Override
public RegisteredClientDTO registerClient(RegisteredClientDTO request,
Authentication authentication) {
Authentication authentication) throws ParseException {

authzChecks(authentication);

Expand Down Expand Up @@ -372,7 +372,7 @@ public RegisteredClientDTO retrieveClient(String clientId, Authentication authen
@Validated(OnDynamicClientUpdate.class)
@Override
public RegisteredClientDTO updateClient(String clientId, RegisteredClientDTO request,
Authentication authentication) {
Authentication authentication) throws ParseException {
authzChecks(authentication);

ClientDetailsEntity oldClient =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@ public boolean isValid(RegisteredClientDTO value, ConstraintValidatorContext con
value.setTokenEndpointAuthMethod(TokenEndpointAuthenticationMethod.client_secret_basic);
} else if (value.getTokenEndpointAuthMethod()
.equals(TokenEndpointAuthenticationMethod.private_key_jwt)
&& Strings.isNullOrEmpty(value.getJwksUri())) {
&& (Strings.isNullOrEmpty(value.getJwksUri()) && Strings.isNullOrEmpty(value.getJwk()))) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("private_key_jwt requires a jwks uri")
context
.buildConstraintViolationWithTemplate("private_key_jwt requires a jwks uri or a jwk value")
.addConstraintViolation();
return false;
}

return true;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static java.util.Objects.isNull;
import static java.util.stream.Collectors.toSet;

import java.text.ParseException;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
Expand All @@ -28,6 +29,9 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.google.common.base.Strings;
import com.nimbusds.jose.jwk.JWKSet;

import it.infn.mw.iam.api.client.registration.ClientRegistrationApiController;
import it.infn.mw.iam.api.common.client.AuthorizationGrantType;
import it.infn.mw.iam.api.common.client.OAuthResponseType;
Expand Down Expand Up @@ -58,7 +62,8 @@ private <T> Set<T> cloneSet(Set<T> stringSet) {
}


public ClientDetailsEntity entityFromClientManagementRequest(RegisteredClientDTO dto) {
public ClientDetailsEntity entityFromClientManagementRequest(RegisteredClientDTO dto)
throws ParseException {
ClientDetailsEntity client = entityFromRegistrationRequest(dto);

if (dto.getAccessTokenValiditySeconds() != null) {
Expand Down Expand Up @@ -98,6 +103,7 @@ public ClientDetailsEntity entityFromClientManagementRequest(RegisteredClientDTO
}

client.setRequireAuthTime(Boolean.valueOf(dto.isRequireAuthTime()));

return client;
}

Expand Down Expand Up @@ -167,7 +173,8 @@ public RegisteredClientDTO registeredClientDtoFromEntity(ClientDetailsEntity ent
return clientDTO;
}

public ClientDetailsEntity entityFromRegistrationRequest(RegisteredClientDTO dto) {
public ClientDetailsEntity entityFromRegistrationRequest(RegisteredClientDTO dto)
throws ParseException {

ClientDetailsEntity client = new ClientDetailsEntity();

Expand All @@ -178,7 +185,11 @@ public ClientDetailsEntity entityFromRegistrationRequest(RegisteredClientDTO dto

client.setClientUri(dto.getClientUri());

client.setJwksUri(dto.getJwksUri());
if (!Strings.isNullOrEmpty(dto.getJwksUri())) {
client.setJwksUri(dto.getJwksUri());
} else if (!Strings.isNullOrEmpty(dto.getJwk())) {
client.setJwks(JWKSet.parse(dto.getJwk()));
}

client.setLogoUri(dto.getLogoUri());
client.setPolicyUri(dto.getPolicyUri());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,18 @@
import java.util.function.Supplier;

import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
import org.mitre.oauth2.service.OAuth2TokenEntityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.oauth2.provider.OAuth2RequestValidator;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import it.infn.mw.iam.audit.events.client.ClientCreatedEvent;
import it.infn.mw.iam.core.oauth.scope.matchers.ScopeMatcherOAuthRequestValidator;
import it.infn.mw.iam.persistence.model.IamAccount;
import it.infn.mw.iam.persistence.model.IamAccountClient;
import it.infn.mw.iam.persistence.repository.client.ClientSpecs;
Expand All @@ -37,26 +41,33 @@

@Service
@Transactional
@SuppressWarnings("deprecation")
public class DefaultClientService implements ClientService {

private final Clock clock;

private final IamClientRepository clientRepo;

private final IamAccountClientRepository accountClientRepo;

private ApplicationEventPublisher eventPublisher;

private OAuth2RequestValidator requestValidator;

private OAuth2TokenEntityService tokenService;

@Autowired
public DefaultClientService(Clock clock, IamClientRepository clientRepo,
IamAccountClientRepository accountClientRepo, ApplicationEventPublisher eventPublisher) {
IamAccountClientRepository accountClientRepo, ApplicationEventPublisher eventPublisher,
OAuth2RequestValidator requestValidator, OAuth2TokenEntityService tokenService) {
this.clock = clock;
this.clientRepo = clientRepo;
this.accountClientRepo = accountClientRepo;
this.eventPublisher = eventPublisher;
this.requestValidator = requestValidator;
this.tokenService = tokenService;
}


@Override
public ClientDetailsEntity saveNewClient(ClientDetailsEntity client) {
client.setCreatedAt(Date.from(clock.instant()));
Expand Down Expand Up @@ -86,14 +97,15 @@ public ClientDetailsEntity linkClientToAccount(ClientDetailsEntity client, IamAc
@Override
public ClientDetailsEntity unlinkClientFromAccount(ClientDetailsEntity client, IamAccount owner) {

accountClientRepo.findByAccountAndClient(owner, client)
.ifPresent(accountClientRepo::delete);
accountClientRepo.findByAccountAndClient(owner, client).ifPresent(accountClientRepo::delete);

return client;
}

@Override
public ClientDetailsEntity updateClient(ClientDetailsEntity client) {

((ScopeMatcherOAuthRequestValidator) requestValidator).invalidateScope(client);
return clientRepo.save(client);
}

Expand Down Expand Up @@ -122,9 +134,28 @@ public Optional<ClientDetailsEntity> findClientByClientIdAndAccount(String clien
@Override
public void deleteClient(ClientDetailsEntity client) {
accountClientRepo.deleteByClientId(client.getId());
deleteTokensByClient(client);
clientRepo.delete(client);
}

private boolean isValidAccessToken(OAuth2AccessTokenEntity a) {
return !(a.getAuthenticationHolder().getScope().contains("registration-token")
|| a.getAuthenticationHolder().getScope().contains("resource-token"));
}

private void deleteTokensByClient(ClientDetailsEntity client) {
// delete all valid access tokens (exclude registration and resource tokens)
tokenService.getAccessTokensForClient(client)
.stream()
.filter(at -> isValidAccessToken(at))
.forEach(at -> {
tokenService.revokeAccessToken(at);
});
// delete all valid refresh tokens
tokenService.getRefreshTokensForClient(client).forEach(rt -> {
tokenService.revokeRefreshToken(rt);
});
}

@Override
public Page<ClientDetailsEntity> findAll(Pageable page) {
Expand Down
Loading

0 comments on commit 8d08924

Please sign in to comment.