Commit 710c9371 authored by Makhtar DIAGNE's avatar Makhtar DIAGNE
Browse files

[TECH] Fix oauth authentication : use same token generation as CAS

parent 644d4a63
...@@ -38,7 +38,7 @@ public class CasExternalRestClientTest extends AbstractServerIdentityBuilder { ...@@ -38,7 +38,7 @@ public class CasExternalRestClientTest extends AbstractServerIdentityBuilder {
.thenReturn(new ResponseEntity<>(HttpStatus.OK)); .thenReturn(new ResponseEntity<>(HttpStatus.OK));
final String superUser = "julien@vitamui.com"; final String superUser = "julien@vitamui.com";
final String authToken = "TOKyyy"; final String authToken = "TOK-1-F8lEhVif0FWjgDF32ov73TtKhE6mflRu";
client.logout(header, authToken, superUser); client.logout(header, authToken, superUser);
final String path = RestApi.CAS_LOGOUT_PATH + "?authToken=" + authToken + "&superUser=" + superUser; final String path = RestApi.CAS_LOGOUT_PATH + "?authToken=" + authToken + "&superUser=" + superUser;
assertThat(argumentCaptor.getValue().toString()).endsWith(path.replaceAll(CommonConstants.EMAIL_SEPARATOR, "%40")); assertThat(argumentCaptor.getValue().toString()).endsWith(path.replaceAll(CommonConstants.EMAIL_SEPARATOR, "%40"));
......
...@@ -39,7 +39,7 @@ public class CasInternalRestClientTest extends AbstractServerIdentityBuilder { ...@@ -39,7 +39,7 @@ public class CasInternalRestClientTest extends AbstractServerIdentityBuilder {
.thenReturn(new ResponseEntity<>(HttpStatus.OK)); .thenReturn(new ResponseEntity<>(HttpStatus.OK));
final String superUser = "julien@vitamui.com"; final String superUser = "julien@vitamui.com";
final String authToken = "TOKxxx"; final String authToken = "TOK-1-F8lEhVif0FWjgDF32ov73TtKhE6mflRu";
client.logout(header, authToken, superUser); client.logout(header, authToken, superUser);
final String path = RestApi.CAS_LOGOUT_PATH + "?authToken=" + authToken + "&superUser=" + superUser; final String path = RestApi.CAS_LOGOUT_PATH + "?authToken=" + authToken + "&superUser=" + superUser;
assertThat(argumentCaptor.getValue().toString()).endsWith(path.replaceAll(CommonConstants.EMAIL_SEPARATOR, "%40")); assertThat(argumentCaptor.getValue().toString()).endsWith(path.replaceAll(CommonConstants.EMAIL_SEPARATOR, "%40"));
......
...@@ -168,6 +168,52 @@ ...@@ -168,6 +168,52 @@
<artifactId>common-private</artifactId> <artifactId>common-private</artifactId>
</dependency> </dependency>
<!-- Apereo CAS Server Core Api Ticket -->
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-core-api-ticket</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</exclusion>
<exclusion>
<groupId>com.zaxxer</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-core-tickets-api</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</exclusion>
<exclusion>
<groupId>com.zaxxer</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Documentation --> <!-- Documentation -->
<dependency> <dependency>
<groupId>io.springfox</groupId> <groupId>io.springfox</groupId>
......
...@@ -49,6 +49,8 @@ import javax.validation.constraints.NotNull; ...@@ -49,6 +49,8 @@ import javax.validation.constraints.NotNull;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils; import org.apache.commons.lang.time.DateUtils;
import org.apereo.cas.util.DefaultUniqueTicketIdGenerator;
import org.apereo.cas.ticket.UniqueTicketIdGenerator;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.MongoTemplate;
...@@ -162,6 +164,8 @@ public class CasInternalService { ...@@ -162,6 +164,8 @@ public class CasInternalService {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static final VitamUILogger LOGGER = VitamUILoggerFactory.getInstance(CasInternalService.class); private static final VitamUILogger LOGGER = VitamUILoggerFactory.getInstance(CasInternalService.class);
private static final UniqueTicketIdGenerator TICKET_GENERATOR = new DefaultUniqueTicketIdGenerator();
@Transactional @Transactional
public void updatePassword(final String email, final String rawPassword) { public void updatePassword(final String email, final String rawPassword) {
final User user = checkUserInformations(email); final User user = checkUserInformations(email);
...@@ -272,7 +276,7 @@ public class CasInternalService { ...@@ -272,7 +276,7 @@ public class CasInternalService {
private void createEventsSubrogation(final UserDto surrogate, final boolean isSubrogation) { private void createEventsSubrogation(final UserDto surrogate, final boolean isSubrogation) {
if (isSubrogation) { if (isSubrogation) {
final Subrogation subro = subrogationRepository.findOneBySurrogate(surrogate.getEmail()); final Subrogation subro = subrogationRepository.findOneBySurrogate(surrogate.getEmail());
EventType type; final EventType type;
if (surrogate.getType().equals(UserTypeEnum.GENERIC)) { if (surrogate.getType().equals(UserTypeEnum.GENERIC)) {
type = EventType.EXT_VITAMUI_START_SURROGATE_GENERIC; type = EventType.EXT_VITAMUI_START_SURROGATE_GENERIC;
} }
...@@ -310,7 +314,7 @@ public class CasInternalService { ...@@ -310,7 +314,7 @@ public class CasInternalService {
} }
final Date nowPlusXMinutes = DateUtils.addMinutes(new Date(), ttlInMinutes); final Date nowPlusXMinutes = DateUtils.addMinutes(new Date(), ttlInMinutes);
token.setUpdatedDate(nowPlusXMinutes); token.setUpdatedDate(nowPlusXMinutes);
token.setId(TOKEN_PREFIX + tokenRepository.generateSuperId().toUpperCase()); token.setId(TICKET_GENERATOR.getNewTicketId(TOKEN_PREFIX));
token.setSurrogation(isSubrogation); token.setSurrogation(isSubrogation);
tokenRepository.save(token); tokenRepository.save(token);
user.setLastConnection(OffsetDateTime.now()); user.setLastConnection(OffsetDateTime.now());
......
...@@ -85,7 +85,7 @@ import fr.gouv.vitamui.iam.internal.server.utils.IamServerUtilsTest; ...@@ -85,7 +85,7 @@ import fr.gouv.vitamui.iam.internal.server.utils.IamServerUtilsTest;
TokenRepository.class }, repositoryBaseClass = VitamUIRepositoryImpl.class) TokenRepository.class }, repositoryBaseClass = VitamUIRepositoryImpl.class)
public final class UserInternalServiceIntegTest extends AbstractLogbookIntegrationTest { public final class UserInternalServiceIntegTest extends AbstractLogbookIntegrationTest {
private static final String TOKEN_VALUE = "TOK1234567890"; private static final String TOKEN_VALUE = "TOK-1-F8lEhVif0FWjgDF32ov73TtKhE6mflRu";
private static final String USER_ID = "userId"; private static final String USER_ID = "userId";
......
...@@ -67,7 +67,7 @@ import fr.gouv.vitamui.iam.security.service.InternalSecurityService; ...@@ -67,7 +67,7 @@ import fr.gouv.vitamui.iam.security.service.InternalSecurityService;
*/ */
public final class UserInternalServiceTest { public final class UserInternalServiceTest {
private static final String TOKEN_VALUE = "TOK1234567890"; private static final String TOKEN_VALUE = "TOK-1-F8lEhVif0FWjgDF32ov73TtKhE6mflRu";
private static final String USER_ID = "userId"; private static final String USER_ID = "userId";
......
...@@ -175,8 +175,8 @@ The call must be a POST request: ...@@ -175,8 +175,8 @@ The call must be a POST request:
The result contains the auth token in a plain response: The result contains the auth token in a plain response:
`access_token=TOK5CE669E223C9741AA6DCD46xxx02C8F6FB9DC98DC25B779&expires_in=28800` `access_token=TOK-1-F8lEhVif0FWjgDF32ov73TtKhE6mflRu&expires_in=28800`
or in a JSON response: or in a JSON response:
`{"access_token":"TOK5CE669E223C9741AA6DCD46xxx02C8F6FB9DC98DC25B779","token_type":"bearer","expires_in":28800}` `{"access_token":"TOK-1-F8lEhVif0FWjgDF32ov73TtKhE6mflRu","token_type":"bearer","expires_in":28800}`
...@@ -111,6 +111,11 @@ ...@@ -111,6 +111,11 @@
<artifactId>cas-server-support-pac4j-core</artifactId> <artifactId>cas-server-support-pac4j-core</artifactId>
<version>${cas.version}</version> <version>${cas.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-pac4j-api</artifactId>
<version>${cas.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.apereo.cas</groupId> <groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-pac4j-core-clients</artifactId> <artifactId>cas-server-support-pac4j-core-clients</artifactId>
...@@ -131,6 +136,11 @@ ...@@ -131,6 +136,11 @@
<artifactId>pac4j-core</artifactId> <artifactId>pac4j-core</artifactId>
<version>${pac4j.version}</version> <version>${pac4j.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.pac4j</groupId>
<artifactId>spring-webmvc-pac4j</artifactId>
<version>${pac4j.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.pac4j</groupId> <groupId>org.pac4j</groupId>
<artifactId>pac4j-saml-opensamlv3</artifactId> <artifactId>pac4j-saml-opensamlv3</artifactId>
......
...@@ -39,9 +39,17 @@ package fr.gouv.vitamui.cas.config; ...@@ -39,9 +39,17 @@ package fr.gouv.vitamui.cas.config;
import fr.gouv.vitamui.cas.authentication.*; import fr.gouv.vitamui.cas.authentication.*;
import fr.gouv.vitamui.cas.pm.IamPasswordManagementService; import fr.gouv.vitamui.cas.pm.IamPasswordManagementService;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.val;
import java.util.Collection;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apereo.cas.CentralAuthenticationService; import org.apereo.cas.CentralAuthenticationService;
import org.apereo.cas.audit.AuditableExecution; import org.apereo.cas.audit.AuditableExecution;
import org.apereo.cas.authentication.*; import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer;
import org.apereo.cas.authentication.AuthenticationHandler;
import org.apereo.cas.authentication.AuthenticationMetaDataPopulator;
import org.apereo.cas.authentication.AuthenticationPostProcessor;
import org.apereo.cas.authentication.principal.PrincipalFactory; import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.authentication.principal.PrincipalResolver; import org.apereo.cas.authentication.principal.PrincipalResolver;
import org.apereo.cas.authentication.surrogate.SurrogateAuthenticationService; import org.apereo.cas.authentication.surrogate.SurrogateAuthenticationService;
...@@ -49,13 +57,27 @@ import org.apereo.cas.configuration.CasConfigurationProperties; ...@@ -49,13 +57,27 @@ import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.pm.PasswordHistoryService; import org.apereo.cas.pm.PasswordHistoryService;
import org.apereo.cas.pm.PasswordManagementService; import org.apereo.cas.pm.PasswordManagementService;
import org.apereo.cas.services.ServicesManager; import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.ticket.*; import org.apereo.cas.support.oauth.authenticator.Authenticators;
import org.apereo.cas.support.oauth.web.OAuth20HandlerInterceptorAdapter;
import org.apereo.cas.support.oauth.web.response.accesstoken.ext.AccessTokenGrantRequestExtractor;
import org.apereo.cas.ticket.BaseTicketCatalogConfigurer;
import org.apereo.cas.ticket.ExpirationPolicyBuilder;
import org.apereo.cas.ticket.TicketCatalog;
import org.apereo.cas.ticket.TicketCatalogConfigurer;
import org.apereo.cas.ticket.TicketDefinition;
import org.apereo.cas.ticket.TicketGrantingTicketFactory;
import org.apereo.cas.ticket.UniqueTicketIdGenerator;
import org.apereo.cas.ticket.accesstoken.OAuth20AccessTokenFactory; import org.apereo.cas.ticket.accesstoken.OAuth20AccessTokenFactory;
import org.apereo.cas.ticket.accesstoken.OAuth20DefaultAccessToken; import org.apereo.cas.ticket.accesstoken.OAuth20DefaultAccessToken;
import org.apereo.cas.ticket.registry.TicketRegistry; import org.apereo.cas.ticket.registry.TicketRegistry;
import org.apereo.cas.token.JwtBuilder; import org.apereo.cas.token.JwtBuilder;
import org.apereo.cas.util.crypto.CipherExecutor; import org.apereo.cas.util.crypto.CipherExecutor;
import org.pac4j.core.client.Client;
import org.pac4j.core.client.DirectClient;
import org.pac4j.core.config.Config;
import org.pac4j.core.context.session.SessionStore; import org.pac4j.core.context.session.SessionStore;
import org.pac4j.core.http.adapter.JEEHttpActionAdapter;
import org.pac4j.springframework.web.SecurityInterceptor;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
...@@ -83,6 +105,7 @@ import fr.gouv.vitamui.iam.external.client.CasExternalRestClient; ...@@ -83,6 +105,7 @@ import fr.gouv.vitamui.iam.external.client.CasExternalRestClient;
import fr.gouv.vitamui.iam.external.client.IamExternalRestClientFactory; import fr.gouv.vitamui.iam.external.client.IamExternalRestClientFactory;
import fr.gouv.vitamui.iam.external.client.IdentityProviderExternalRestClient; import fr.gouv.vitamui.iam.external.client.IdentityProviderExternalRestClient;
import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.web.servlet.HandlerInterceptor;
/** /**
* Configure all beans to customize the CAS server. * Configure all beans to customize the CAS server.
...@@ -196,6 +219,38 @@ public class AppConfig extends BaseTicketCatalogConfigurer { ...@@ -196,6 +219,38 @@ public class AppConfig extends BaseTicketCatalogConfigurer {
@Value("${vitamui.cas.identity}") @Value("${vitamui.cas.identity}")
private String casIdentity; private String casIdentity;
@Autowired
@Qualifier("oauthSecConfig")
private ObjectProvider<Config> oauthSecConfig;
@Autowired
@Qualifier("accessTokenGrantRequestExtractors")
private Collection<AccessTokenGrantRequestExtractor> accessTokenGrantRequestExtractors;
@Bean
public SecurityInterceptor requiresAuthenticationAuthorizeInterceptor() {
val interceptor = new SecurityInterceptor(oauthSecConfig.getObject(), Authenticators.CAS_OAUTH_CLIENT, JEEHttpActionAdapter.INSTANCE);
interceptor.setAuthorizers("none");
return interceptor;
}
@Bean
public SecurityInterceptor requiresAuthenticationAccessTokenInterceptor() {
val secConfig = oauthSecConfig.getObject();
val clients =
Objects.requireNonNull(secConfig).getClients().findAllClients().stream().filter(client -> client instanceof DirectClient).map(Client::getName)
.collect(Collectors.joining(","));
val interceptor = new SecurityInterceptor(oauthSecConfig.getObject(), clients, JEEHttpActionAdapter.INSTANCE);
interceptor.setAuthorizers("none");
return interceptor;
}
@Bean
public HandlerInterceptor oauthHandlerInterceptorAdapter() {
return new OAuth20HandlerInterceptorAdapter(requiresAuthenticationAccessTokenInterceptor(), requiresAuthenticationAuthorizeInterceptor(),
accessTokenGrantRequestExtractors);
}
@Bean @Bean
public UserAuthenticationHandler userAuthenticationHandler() { public UserAuthenticationHandler userAuthenticationHandler() {
return new UserAuthenticationHandler(servicesManager, principalFactory, casRestClient(), utils(), ipHeaderName); return new UserAuthenticationHandler(servicesManager, principalFactory, casRestClient(), utils(), ipHeaderName);
......
...@@ -468,6 +468,30 @@ ...@@ -468,6 +468,30 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- Apereo CAS Server Core Api Ticket -->
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-core-api-ticket</artifactId>
<version>${cas.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-core-tickets-api</artifactId>
<version>${cas.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Web --> <!-- Web -->
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>javax.servlet</groupId>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment