- * Copyright (c) 2022-2023 the original author or authors. + * Copyright (c) 2022-2025 the original author or authors. *
* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/AuditConfig.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/AuditConfig.java index dc6accc..07b93dd 100644 --- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/AuditConfig.java +++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/AuditConfig.java @@ -1,7 +1,7 @@ /** * The MIT License (MIT) *
- * Copyright (c) 2022-2023 the original author or authors. + * Copyright (c) 2022-2025 the original author or authors. *
* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/SecurityConfig.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/SecurityConfig.java index 479a942..ebaa6e2 100644 --- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/SecurityConfig.java +++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/SecurityConfig.java @@ -1,7 +1,7 @@ /** * The MIT License (MIT) *
- * Copyright (c) 2022-2023 the original author or authors. + * Copyright (c) 2022-2025 the original author or authors. *
* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,9 +31,8 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; -import com.bernardomg.example.spring.security.ws.basic.security.user.persistence.repository.PrivilegeRepository; -import com.bernardomg.example.spring.security.ws.basic.security.user.persistence.repository.UserRepository; -import com.bernardomg.example.spring.security.ws.basic.security.userdetails.PersistentUserDetailsService; +import com.bernardomg.example.spring.security.ws.basic.springframework.userdetails.UserDomainDetailsService; +import com.bernardomg.example.spring.security.ws.basic.user.domain.repository.UserRepository; /** * Security configuration. @@ -67,14 +66,11 @@ public PasswordEncoder getPasswordEncoder() { * * @param userRepository * repository for finding users - * @param privilegeRepository - * repository for finding user privileges * @return the user details service */ @Bean("userDetailsService") - public UserDetailsService getUserDetailsService(final UserRepository userRepository, - final PrivilegeRepository privilegeRepository) { - return new PersistentUserDetailsService(userRepository, privilegeRepository); + public UserDetailsService getUserDetailsService(final UserRepository userRepository) { + return new UserDomainDetailsService(userRepository); } } diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/WebConfiguration.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/WebConfiguration.java index 2f51f16..8099412 100644 --- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/WebConfiguration.java +++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/WebConfiguration.java @@ -1,7 +1,7 @@ /** * The MIT License (MIT) *
- * Copyright (c) 2022-2023 the original author or authors. + * Copyright (c) 2022-2025 the original author or authors. *
* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/WebSecurityConfig.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/WebSecurityConfig.java index 45e9af7..c2bc832 100644 --- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/WebSecurityConfig.java +++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/WebSecurityConfig.java @@ -1,7 +1,7 @@ /** * The MIT License (MIT) *
- * Copyright (c) 2022-2023 the original author or authors. + * Copyright (c) 2022-2025 the original author or authors. *
* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,8 +24,6 @@ package com.bernardomg.example.spring.security.ws.basic.config; -import java.util.Arrays; - import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.Customizer; @@ -34,10 +32,13 @@ import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer; import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; +import org.springframework.web.servlet.handler.HandlerMappingIntrospector; -import com.bernardomg.example.spring.security.ws.basic.security.configuration.WhitelistRequestCustomizer; +import com.bernardomg.example.spring.security.ws.basic.springframework.web.ErrorResponseAuthenticationEntryPoint; /** * Web security configuration. @@ -61,6 +62,8 @@ public WebSecurityConfig() { * * @param http * HTTP security component + * @param introspector + * utility class to find routes * @param userDetailsService * user details service * @return web security filter chain with all authentication requirements @@ -69,16 +72,31 @@ public WebSecurityConfig() { */ @Bean("webSecurityFilterChain") public SecurityFilterChain getWebSecurityFilterChain(final HttpSecurity http, - final UserDetailsService userDetailsService) throws Exception { + final HandlerMappingIntrospector introspector, final UserDetailsService userDetailsService) + throws Exception { + final MvcRequestMatcher.Builder mvc; + + mvc = new MvcRequestMatcher.Builder(introspector); http // Whitelist access - .authorizeHttpRequests(new WhitelistRequestCustomizer(Arrays.asList("/actuator/**", "/login/**"))) + .authorizeHttpRequests(c -> c + .requestMatchers(mvc.pattern("/actuator/**"), mvc.pattern("/login/**"), mvc.pattern("/favicon.ico"), + mvc.pattern("/error/**")) + .permitAll()) + // Authenticate all others + .authorizeHttpRequests(c -> c.anyRequest() + .authenticated()) + .httpBasic(Customizer.withDefaults()) + // CSRF and CORS .csrf(CsrfConfigurer::disable) - .cors(cors -> {}) + .cors(Customizer.withDefaults()) + // Authentication error handling + .exceptionHandling(handler -> handler.authenticationEntryPoint(new ErrorResponseAuthenticationEntryPoint())) + // Stateless + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + // Disable login and logout forms .formLogin(FormLoginConfigurer::disable) - .logout(LogoutConfigurer::disable) - // Activates HTTP Basic authentication - .httpBasic(Customizer.withDefaults()); + .logout(LogoutConfigurer::disable); http.userDetailsService(userDetailsService); diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/package-info.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/package-info.java index bf69e2d..8339718 100644 --- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/package-info.java +++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/config/package-info.java @@ -1,7 +1,7 @@ /** * The MIT License (MIT) *
- * Copyright (c) 2022-2023 the original author or authors. + * Copyright (c) 2022-2025 the original author or authors. *
* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/controller/ExampleEntityController.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/controller/ExampleEntityController.java deleted file mode 100644 index b43a2a4..0000000 --- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/controller/ExampleEntityController.java +++ /dev/null @@ -1,107 +0,0 @@ -/** - * The MIT License (MIT) - *
- * Copyright (c) 2022-2023 the original author or authors. - *
- * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - *
- * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.bernardomg.example.spring.security.ws.basic.domain.entity.controller;
-
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import com.bernardomg.example.spring.security.ws.basic.domain.entity.model.ExampleEntity;
-import com.bernardomg.example.spring.security.ws.basic.domain.entity.service.ExampleEntityService;
-
-import lombok.AllArgsConstructor;
-import lombok.NonNull;
-
-/**
- * Rest controller for the example entities.
- *
- * @author Bernardo Martínez Garrido
- */
-@RestController
-@RequestMapping("/rest/entity")
-@AllArgsConstructor
-public class ExampleEntityController {
-
- /**
- * Example entity service.
- */
- @NonNull
- private final ExampleEntityService exampleEntityService;
-
- /**
- * Creates an entity.
- *
- * @param entity
- * entity to create
- * @return the created entity
- */
- @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE)
- public ExampleEntity create(final ExampleEntity entity) {
- return exampleEntityService.create(entity);
- }
-
- /**
- * Deletes the entity for the received id.
- *
- * @param id
- * id of the entity to delete
- * @return {@code true} if it was deleted, {@code false} otherwise
- */
- @DeleteMapping(path = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
- public Boolean delete(@PathVariable("id") final Long id) {
- return exampleEntityService.delete(id);
- }
-
- /**
- * Returns all the entities.
- *
- * @return all the entities
- */
- @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
- public Iterable
- * Copyright (c) 2022-2023 the original author or authors.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/**
- * Model classes.
- *
- * These represent the main sets of data which the application works with.
- */
-
-package com.bernardomg.example.spring.security.ws.basic.domain.entity.model;
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/persistence/repository/package-info.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/persistence/repository/package-info.java
deleted file mode 100644
index 2a0470d..0000000
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/persistence/repository/package-info.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * The MIT License (MIT)
- *
- * Copyright (c) 2022-2023 the original author or authors.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-/**
- * Repositories.
- *
- * Similar to a DAO, a repository is a pattern which allows handling the persistence layer as if it was a collection,
- * where entities are stored and read from.
- */
-
-package com.bernardomg.example.spring.security.ws.basic.domain.entity.persistence.repository;
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/service/DefaultExampleEntityService.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/service/DefaultExampleEntityService.java
deleted file mode 100644
index 6a925e5..0000000
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/service/DefaultExampleEntityService.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * The MIT License (MIT)
- *
- * Copyright (c) 2022-2023 the original author or authors.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.bernardomg.example.spring.security.ws.basic.domain.entity.service;
-
-import java.util.stream.Collectors;
-
-import org.springframework.stereotype.Service;
-
-import com.bernardomg.example.spring.security.ws.basic.domain.entity.model.DtoExampleEntity;
-import com.bernardomg.example.spring.security.ws.basic.domain.entity.model.ExampleEntity;
-import com.bernardomg.example.spring.security.ws.basic.domain.entity.model.PersistentExampleEntity;
-import com.bernardomg.example.spring.security.ws.basic.domain.entity.persistence.repository.ExampleEntityRepository;
-
-import lombok.AllArgsConstructor;
-
-/**
- * Default implementation of the example entity service.
- *
- * @author Bernardo Martínez Garrido
- */
-@Service
-@AllArgsConstructor
-public final class DefaultExampleEntityService implements ExampleEntityService {
-
- /**
- * Repository for the domain entities handled by the service.
- */
- private final ExampleEntityRepository entityRepository;
-
- @Override
- public final ExampleEntity create(final ExampleEntity data) {
- final PersistentExampleEntity entity;
- final PersistentExampleEntity saved;
-
- entity = toEntity(data);
-
- saved = entityRepository.save(entity);
-
- return toDto(saved);
- }
-
- @Override
- public final Boolean delete(final Long id) {
- entityRepository.deleteById(id);
-
- return true;
- }
-
- @Override
- public final Iterable
- * Copyright (c) 2022-2023 the original author or authors.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.bernardomg.example.spring.security.ws.basic.domain.entity.service;
-
-import org.springframework.security.access.prepost.PreAuthorize;
-
-import com.bernardomg.example.spring.security.ws.basic.domain.entity.model.ExampleEntity;
-
-/**
- * Service for the example entity domain.
- *
- * This is a domain service just to allow the endpoints querying the entities they are asked for.
- *
- * @author Bernardo Martínez Garrido
- */
-public interface ExampleEntityService {
-
- /**
- * Creates the received entity.
- *
- * @param entity
- * entity to create
- * @return the entity created
- */
- @PreAuthorize("hasAuthority('CREATE_DATA')")
- public ExampleEntity create(final ExampleEntity entity);
-
- /**
- * Deletes the entity for the received id.
- *
- * @param id
- * entity id
- * @return {@code true} if it was deleted, {@code false} otherwise
- */
- @PreAuthorize("hasAuthority('DELETE_DATA')")
- public Boolean delete(final Long id);
-
- /**
- * Returns all the entities.
- *
- * @return all the entities
- */
- @PreAuthorize("hasAuthority('READ_DATA')")
- public Iterable
- * Copyright (c) 2022 the original author or authors.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.bernardomg.example.spring.security.ws.basic.login.usecase.service;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
-import java.util.Optional;
-
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.stereotype.Service;
-
-import com.bernardomg.example.spring.security.ws.basic.login.domain.model.LoginStatus;
-
-import lombok.AllArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-
-/**
- * Default implementation of the login service.
- *
- * @author Bernardo Martínez Garrido
- *
- */
-@Service
-@Slf4j
-@AllArgsConstructor
-public final class DefaultLoginService implements LoginService {
-
- /**
- * Password encoder, for validating passwords.
- */
- private final PasswordEncoder passwordEncoder;
-
- /**
- * User details service, to find and validate users.
- */
- private final UserDetailsService userDetailsService;
-
- @Override
- public final LoginStatus login(final String username, final String password) {
- final Boolean logged;
- final LoginStatus status;
- final String token;
- Optional
- * Copyright (c) 2022 the original author or authors.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.bernardomg.example.spring.security.ws.basic.login.usecase.service;
-
-import com.bernardomg.example.spring.security.ws.basic.login.domain.model.LoginStatus;
-
-/**
- * Login service. Takes the user credentials and returns a token.
- *
- * @author Bernardo Martínez Garrido
- *
- */
-public interface LoginService {
-
- /**
- * Receives credentials and returns the login status. If it was valid then it contains a token.
- *
- * @param username
- * username to authenticate
- * @param password
- * password to authenticate
- * @return login status
- */
- public LoginStatus login(final String username, final String password);
-
-}
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/package-info.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/package-info.java
index 308962e..31c804d 100644
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/package-info.java
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/package-info.java
@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/person/adapter/inbound/user/repository/UserPersonRepository.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/person/adapter/inbound/user/repository/UserPersonRepository.java
new file mode 100644
index 0000000..558942d
--- /dev/null
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/person/adapter/inbound/user/repository/UserPersonRepository.java
@@ -0,0 +1,79 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022-2025 the original author or authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.bernardomg.example.spring.security.ws.basic.person.adapter.inbound.user.repository;
+
+import java.util.Collection;
+import java.util.Objects;
+
+import org.springframework.stereotype.Repository;
+
+import com.bernardomg.example.spring.security.ws.basic.person.domain.model.Person;
+import com.bernardomg.example.spring.security.ws.basic.person.domain.repository.PersonRepository;
+import com.bernardomg.example.spring.security.ws.basic.user.domain.model.User;
+import com.bernardomg.example.spring.security.ws.basic.user.domain.repository.UserRepository;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Person repository which takes the data from the users. Reads from the users repository, and maps into {@code Person}.
+ *
+ * @author Bernardo Martínez Garrido
+ */
+@Slf4j
+@Repository
+public final class UserPersonRepository implements PersonRepository {
+
+ /**
+ * User repository. The data for the persons is taken from here.
+ */
+ private final UserRepository userRepository;
+
+ public UserPersonRepository(final UserRepository userRepo) {
+ super();
+
+ userRepository = Objects.requireNonNull(userRepo, "Received a null pointer as user repository");
+ }
+
+ @Override
+ public final Collection
+ * Copyright (c) 2022-2025 the original author or authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * User-based person repository.
+ */
+
+package com.bernardomg.example.spring.security.ws.basic.person.adapter.inbound.user.repository;
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/login/adapter/outbound/rest/controller/LoginController.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/person/adapter/outbound/rest/controller/PersonController.java
similarity index 57%
rename from src/main/java/com/bernardomg/example/spring/security/ws/basic/login/adapter/outbound/rest/controller/LoginController.java
rename to src/main/java/com/bernardomg/example/spring/security/ws/basic/person/adapter/outbound/rest/controller/PersonController.java
index e3388fd..69249f4 100644
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/login/adapter/outbound/rest/controller/LoginController.java
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/person/adapter/outbound/rest/controller/PersonController.java
@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
- * Copyright (c) 2022 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,45 +22,37 @@
* SOFTWARE.
*/
-package com.bernardomg.example.spring.security.ws.basic.login.adapter.outbound.rest.controller;
+package com.bernardomg.example.spring.security.ws.basic.person.adapter.outbound.rest.controller;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
-import com.bernardomg.example.spring.security.ws.basic.login.adapter.outbound.rest.model.UserForm;
-import com.bernardomg.example.spring.security.ws.basic.login.domain.model.LoginStatus;
-import com.bernardomg.example.spring.security.ws.basic.login.usecase.service.LoginService;
+import com.bernardomg.example.spring.security.ws.basic.person.domain.model.Person;
+import com.bernardomg.example.spring.security.ws.basic.person.usecase.service.PersonService;
import lombok.AllArgsConstructor;
/**
- * Login controller. Allows a user to log into the application.
+ * Person REST controller.
*
* @author Bernardo Martínez Garrido
*
*/
@RestController
-@RequestMapping("/login")
+@RequestMapping("/person")
@AllArgsConstructor
-public class LoginController {
+public class PersonController {
/**
- * Login service.
+ * Person service.
*/
- private final LoginService service;
+ private final PersonService service;
- /**
- * Logs in a user.
- *
- * @param user
- * user details
- * @return the login status after the login attempt
- */
- @PostMapping
- public LoginStatus login(@RequestBody final UserForm user) {
- return service.login(user.username(), user.password());
+ @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
+ public Iterable
- * Copyright (c) 2022 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
*/
/**
- * Login controller model.
+ * Person controller.
*/
-package com.bernardomg.example.spring.security.ws.basic.login.adapter.outbound.rest.model;
+package com.bernardomg.example.spring.security.ws.basic.person.adapter.outbound.rest.controller;
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/login/adapter/outbound/rest/model/UserForm.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/person/domain/model/Person.java
similarity index 82%
rename from src/main/java/com/bernardomg/example/spring/security/ws/basic/login/adapter/outbound/rest/model/UserForm.java
rename to src/main/java/com/bernardomg/example/spring/security/ws/basic/person/domain/model/Person.java
index 5cb6c71..347fda7 100644
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/login/adapter/outbound/rest/model/UserForm.java
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/person/domain/model/Person.java
@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
- * Copyright (c) 2022 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,14 +22,13 @@
* SOFTWARE.
*/
-package com.bernardomg.example.spring.security.ws.basic.login.adapter.outbound.rest.model;
+package com.bernardomg.example.spring.security.ws.basic.person.domain.model;
/**
- * Contains all the data for a login attempt.
+ * Person.
*
* @author Bernardo Martínez Garrido
- *
*/
-public record UserForm(String username, String password) {
+public record Person(String id, String name) {
}
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/login/usecase/service/package-info.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/person/domain/model/package-info.java
similarity index 88%
rename from src/main/java/com/bernardomg/example/spring/security/ws/basic/login/usecase/service/package-info.java
rename to src/main/java/com/bernardomg/example/spring/security/ws/basic/person/domain/model/package-info.java
index b1227e4..d486416 100644
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/login/usecase/service/package-info.java
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/person/domain/model/package-info.java
@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
- * Copyright (c) 2022 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
*/
/**
- * Login services.
+ * Person model.
*/
-package com.bernardomg.example.spring.security.ws.basic.login.usecase.service;
+package com.bernardomg.example.spring.security.ws.basic.person.domain.model;
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/person/domain/repository/PersonRepository.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/person/domain/repository/PersonRepository.java
new file mode 100644
index 0000000..05d87ac
--- /dev/null
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/person/domain/repository/PersonRepository.java
@@ -0,0 +1,45 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022-2025 the original author or authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.bernardomg.example.spring.security.ws.basic.person.domain.repository;
+
+import java.util.Collection;
+
+import com.bernardomg.example.spring.security.ws.basic.person.domain.model.Person;
+
+/**
+ * Person repository.
+ *
+ * @author Bernardo Martínez Garrido
+ */
+public interface PersonRepository {
+
+ /**
+ * Returns all the people.
+ *
+ * @return all the people
+ */
+ public Collection
+ * Copyright (c) 2022-2025 the original author or authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * Person repository.
+ */
+
+package com.bernardomg.example.spring.security.ws.basic.person.domain.repository;
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/persistence/repository/ExampleEntityRepository.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/person/usecase/service/DefaultPersonService.java
similarity index 54%
rename from src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/persistence/repository/ExampleEntityRepository.java
rename to src/main/java/com/bernardomg/example/spring/security/ws/basic/person/usecase/service/DefaultPersonService.java
index 2723b87..2b16039 100644
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/persistence/repository/ExampleEntityRepository.java
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/person/usecase/service/DefaultPersonService.java
@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,32 +22,43 @@
* SOFTWARE.
*/
-package com.bernardomg.example.spring.security.ws.basic.domain.entity.persistence.repository;
+package com.bernardomg.example.spring.security.ws.basic.person.usecase.service;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.jpa.repository.JpaRepository;
+import java.util.Collection;
+import java.util.Objects;
-import com.bernardomg.example.spring.security.ws.basic.domain.entity.model.PersistentExampleEntity;
+import org.springframework.stereotype.Service;
+
+import com.bernardomg.example.spring.security.ws.basic.person.domain.model.Person;
+import com.bernardomg.example.spring.security.ws.basic.person.domain.repository.PersonRepository;
+
+import lombok.extern.slf4j.Slf4j;
/**
- * Spring-JPA repository for {@link PersistentExampleEntity}.
- *
- * This is a simple repository just to allow the endpoints querying the entities they are asked for.
+ * Default person service, which just takes the data from the person repository.
*
* @author Bernardo Martínez Garrido
*/
-public interface ExampleEntityRepository extends JpaRepository
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,21 +22,24 @@
* SOFTWARE.
*/
-package com.bernardomg.example.spring.security.ws.basic.domain.entity.model;
+package com.bernardomg.example.spring.security.ws.basic.person.usecase.service;
-import lombok.Data;
+import java.util.Collection;
-@Data
-public final class DtoExampleEntity implements ExampleEntity {
+import com.bernardomg.example.spring.security.ws.basic.person.domain.model.Person;
- /**
- * Entity id.
- */
- private Long id;
+/**
+ * Person service.
+ *
+ * @author Bernardo Martínez Garrido
+ */
+public interface PersonService {
/**
- * Entity name.
+ * Returns all the people.
+ *
+ * @return all the people
*/
- private String name;
+ public Collection
- * Copyright (c) 2022 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
*/
/**
- * Login model.
+ * Person service.
*/
-package com.bernardomg.example.spring.security.ws.basic.login.domain.model;
+package com.bernardomg.example.spring.security.ws.basic.person.usecase.service;
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/security/configuration/WhitelistRequestCustomizer.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/security/configuration/WhitelistRequestCustomizer.java
deleted file mode 100644
index 1b6ccf8..0000000
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/security/configuration/WhitelistRequestCustomizer.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * The MIT License (MIT)
- *
- * Copyright (c) 2022-2024 the original author or authors.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.bernardomg.example.spring.security.ws.basic.security.configuration;
-
-import java.util.Collection;
-import java.util.Objects;
-
-import org.springframework.security.config.Customizer;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
-
-/**
- * White list request access configuration. Allows unauthorized access to the routes in the white list. Any other route
- * requires authorization.
- *
- * @author Bernardo Martínez Garrido
- *
- */
-public final class WhitelistRequestCustomizer implements
- Customizer
- * Copyright (c) 2022-2023 the original author or authors.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.bernardomg.example.spring.security.ws.basic.security.user.persistence.repository;
-
-import java.util.Collection;
-
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.repository.query.Param;
-
-import com.bernardomg.example.spring.security.ws.basic.security.user.persistence.model.PersistentPrivilege;
-
-/**
- * Repository for privileges.
- *
- * @author Bernardo Martínez Garrido
- *
- */
-public interface PrivilegeRepository extends JpaRepository
- * Copyright (c) 2022-2023 the original author or authors.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.bernardomg.example.spring.security.ws.basic.security.userdetails;
-
-import java.util.Collection;
-import java.util.Locale;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.userdetails.User;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-
-import com.bernardomg.example.spring.security.ws.basic.security.user.persistence.model.PersistentPrivilege;
-import com.bernardomg.example.spring.security.ws.basic.security.user.persistence.model.PersistentUser;
-import com.bernardomg.example.spring.security.ws.basic.security.user.persistence.repository.PrivilegeRepository;
-import com.bernardomg.example.spring.security.ws.basic.security.user.persistence.repository.UserRepository;
-
-import lombok.extern.slf4j.Slf4j;
-
-/**
- * User details service which takes the user data from the persistence layer.
- *
- * Makes use of repositories, which will return the user and his privileges.
- *
- * The user search is based on the username, and is case insensitive. As the persisted user details are expected to
- * contain the username in lower case.
- *
- * Privileges are read moving through the model. The service receives a username and then finds the privileges assigned
- * to the related user:
- *
- * {@code user -> role -> privileges}
- *
- * These privileges are used to create the granted authorities.
- *
- * When loading users any of these cases throws a {@code UsernameNotFoundException}:
- *
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
-package com.bernardomg.example.spring.security.ws.basic.security.audit;
+package com.bernardomg.example.spring.security.ws.basic.springframework.audit;
import java.util.Map;
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/security/audit/package-info.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/springframework/audit/package-info.java
similarity index 89%
rename from src/main/java/com/bernardomg/example/spring/security/ws/basic/security/audit/package-info.java
rename to src/main/java/com/bernardomg/example/spring/security/ws/basic/springframework/audit/package-info.java
index e45fc71..fe01e7e 100644
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/security/audit/package-info.java
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/springframework/audit/package-info.java
@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,4 +26,4 @@
* Audit components.
*/
-package com.bernardomg.example.spring.security.ws.basic.security.audit;
+package com.bernardomg.example.spring.security.ws.basic.springframework.audit;
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/springframework/userdetails/UserDomainDetailsService.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/springframework/userdetails/UserDomainDetailsService.java
new file mode 100644
index 0000000..42b484d
--- /dev/null
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/springframework/userdetails/UserDomainDetailsService.java
@@ -0,0 +1,162 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022-2025 the original author or authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.bernardomg.example.spring.security.ws.basic.springframework.userdetails;
+
+import java.util.Collection;
+import java.util.Locale;
+import java.util.Objects;
+
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+
+import com.bernardomg.example.spring.security.ws.basic.user.domain.model.Privilege;
+import com.bernardomg.example.spring.security.ws.basic.user.domain.model.User;
+import com.bernardomg.example.spring.security.ws.basic.user.domain.repository.UserRepository;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * User details service which takes the user data from the persistence layer.
+ *
+ * Makes use of repositories, which will return the user and his privileges.
+ *
+ * The user search is based on the username, and is case insensitive. As the persisted user details are expected to
+ * contain the username in lower case.
+ *
+ * Privileges are read moving through the model. The service receives a username and then finds the privileges assigned
+ * to the related user:
+ *
+ * {@code user -> role -> privileges}
+ *
+ * These privileges are used to create the granted authorities.
+ *
+ * When loading users any of these cases throws a {@code UsernameNotFoundException}:
+ *
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,4 +26,4 @@
* User details components.
*/
-package com.bernardomg.example.spring.security.ws.basic.security.userdetails;
+package com.bernardomg.example.spring.security.ws.basic.springframework.userdetails;
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/security/entrypoint/ErrorResponseAuthenticationEntryPoint.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/springframework/web/ErrorResponseAuthenticationEntryPoint.java
similarity index 95%
rename from src/main/java/com/bernardomg/example/spring/security/ws/basic/security/entrypoint/ErrorResponseAuthenticationEntryPoint.java
rename to src/main/java/com/bernardomg/example/spring/security/ws/basic/springframework/web/ErrorResponseAuthenticationEntryPoint.java
index 5f0b635..dd6b7b4 100644
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/security/entrypoint/ErrorResponseAuthenticationEntryPoint.java
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/springframework/web/ErrorResponseAuthenticationEntryPoint.java
@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
-package com.bernardomg.example.spring.security.ws.basic.security.entrypoint;
+package com.bernardomg.example.spring.security.ws.basic.springframework.web;
import java.io.IOException;
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/security/entrypoint/package-info.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/springframework/web/package-info.java
similarity index 87%
rename from src/main/java/com/bernardomg/example/spring/security/ws/basic/security/entrypoint/package-info.java
rename to src/main/java/com/bernardomg/example/spring/security/ws/basic/springframework/web/package-info.java
index 759b285..b51a03e 100644
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/security/entrypoint/package-info.java
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/springframework/web/package-info.java
@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
*/
/**
- * JWT entry points.
+ * Security entry points.
*/
-package com.bernardomg.example.spring.security.ws.basic.security.entrypoint;
+package com.bernardomg.example.spring.security.ws.basic.springframework.web;
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/security/user/persistence/model/PersistentPrivilege.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/user/adapter/inbound/jpa/model/PrivilegeEntity.java
similarity index 84%
rename from src/main/java/com/bernardomg/example/spring/security/ws/basic/security/user/persistence/model/PersistentPrivilege.java
rename to src/main/java/com/bernardomg/example/spring/security/ws/basic/user/adapter/inbound/jpa/model/PrivilegeEntity.java
index 5a03643..35ca952 100644
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/security/user/persistence/model/PersistentPrivilege.java
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/user/adapter/inbound/jpa/model/PrivilegeEntity.java
@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
-package com.bernardomg.example.spring.security.ws.basic.security.user.persistence.model;
+package com.bernardomg.example.spring.security.ws.basic.user.adapter.inbound.jpa.model;
import java.io.Serializable;
@@ -36,10 +36,7 @@
import lombok.Data;
/**
- * Persistent privilege data.
- *
- * JPA entities shouldn't end mixed up with the domain model. For this reason this class won't extend any generic
- * interface, and instead is a JPA POJO.
+ * Privilege entity.
*
* @author Bernardo Martínez Garrido
*
@@ -49,7 +46,7 @@
@Table(name = "privileges")
@TableGenerator(name = "seq_privileges_id", table = "sequences", pkColumnName = "sequence", valueColumnName = "count",
allocationSize = 1)
-public class PersistentPrivilege implements Serializable {
+public class PrivilegeEntity implements Serializable {
/**
* Serialization id.
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/model/PersistentExampleEntity.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/user/adapter/inbound/jpa/model/RoleEntity.java
similarity index 54%
rename from src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/model/PersistentExampleEntity.java
rename to src/main/java/com/bernardomg/example/spring/security/ws/basic/user/adapter/inbound/jpa/model/RoleEntity.java
index b9f87e1..511cbba 100644
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/model/PersistentExampleEntity.java
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/user/adapter/inbound/jpa/model/RoleEntity.java
@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,51 +22,61 @@
* SOFTWARE.
*/
-package com.bernardomg.example.spring.security.ws.basic.domain.entity.model;
+package com.bernardomg.example.spring.security.ws.basic.user.adapter.inbound.jpa.model;
import java.io.Serializable;
+import java.util.Collection;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.JoinTable;
+import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
-import jakarta.persistence.Transient;
+import jakarta.persistence.TableGenerator;
import lombok.Data;
/**
- * Persistent entity for the example application.
- *
- * This makes use of JPA annotations for the persistence configuration.
+ * Role entity.
*
* @author Bernardo Martínez Garrido
+ *
*/
-@Entity(name = "ExampleEntity")
-@Table(name = "example_entities")
@Data
-public class PersistentExampleEntity implements Serializable {
+@Entity(name = "Role")
+@Table(name = "roles")
+@TableGenerator(name = "seq_roles_id", table = "sequences", pkColumnName = "sequence", valueColumnName = "count",
+ allocationSize = 1)
+public class RoleEntity implements Serializable {
/**
- * Serialization ID.
+ * Serialization id.
*/
- @Transient
- private static final long serialVersionUID = 1328776989450853491L;
+ private static final long serialVersionUID = 8513041662486312372L;
/**
- * Entity's ID.
+ * Entity id.
*/
@Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @GeneratedValue(strategy = GenerationType.TABLE, generator = "seq_privileges_id")
@Column(name = "id", nullable = false, unique = true)
- private Long id = -1L;
+ private Long id;
+
+ /**
+ * Privilege name.
+ */
+ @Column(name = "name", nullable = false, unique = true, length = 60)
+ private String name;
/**
- * Name of the entity.
- *
- * This is to have additional data apart from the id, to be used on the tests.
+ * Privileges.
*/
- @Column(name = "name", nullable = false, unique = true)
- private String name = "";
+ @OneToMany
+ @JoinTable(name = "role_privileges", joinColumns = { @JoinColumn(name = "role_id", referencedColumnName = "id") },
+ inverseJoinColumns = { @JoinColumn(name = "privilege_id", referencedColumnName = "id") })
+ private Collection
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,25 +22,26 @@
* SOFTWARE.
*/
-package com.bernardomg.example.spring.security.ws.basic.security.user.persistence.model;
+package com.bernardomg.example.spring.security.ws.basic.user.adapter.inbound.jpa.model;
import java.io.Serializable;
+import java.util.Collection;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.JoinTable;
+import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.persistence.TableGenerator;
import jakarta.persistence.Transient;
import lombok.Data;
/**
- * Persistent user data.
- *
- * JPA entities shouldn't end mixed up with the domain model. For this reason this class won't extend any generic
- * interface, and instead is a JPA POJO.
+ * User entity.
*
* @author Bernardo Martínez Garrido
*
@@ -50,37 +51,37 @@
@Table(name = "users")
@TableGenerator(name = "seq_users_id", table = "sequences", pkColumnName = "sequence", valueColumnName = "count",
allocationSize = 1)
-public class PersistentUser implements Serializable {
+public class UserEntity implements Serializable {
/**
* Serialization id.
*/
@Transient
- private static final long serialVersionUID = 4807136960800402795L;
+ private static final long serialVersionUID = 4807136960800402795L;
/**
* User expired flag.
*/
@Column(name = "credentials_expired", nullable = false)
- private Boolean credentialsExpired;
+ private Boolean credentialsExpired;
/**
* User email.
*/
@Column(name = "email", nullable = false, length = 60)
- private String email;
+ private String email;
/**
* User enabled flag.
*/
@Column(name = "enabled", nullable = false)
- private Boolean enabled;
+ private Boolean enabled;
/**
* User expired flag.
*/
@Column(name = "expired", nullable = false)
- private Boolean expired;
+ private Boolean expired;
/**
* Entity id.
@@ -88,30 +89,38 @@ public class PersistentUser implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "seq_users_id")
@Column(name = "id", nullable = false, unique = true)
- private Long id;
+ private Long id;
/**
* User locked flag.
*/
@Column(name = "locked", nullable = false)
- private Boolean locked;
+ private Boolean locked;
/**
* User name.
*/
@Column(name = "name", nullable = false, unique = true, length = 60)
- private String name;
+ private String name;
/**
* User password.
*/
@Column(name = "password", nullable = false, length = 60)
- private String password;
+ private String password;
+
+ /**
+ * Roles.
+ */
+ @OneToMany
+ @JoinTable(name = "user_roles", joinColumns = { @JoinColumn(name = "user_id", referencedColumnName = "id") },
+ inverseJoinColumns = { @JoinColumn(name = "role_id", referencedColumnName = "id") })
+ private Collection
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
*/
/**
- * Controller classes.
+ * JPA user model.
*/
-package com.bernardomg.example.spring.security.ws.basic.domain.entity.controller;
+package com.bernardomg.example.spring.security.ws.basic.user.adapter.inbound.jpa.model;
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/user/adapter/inbound/jpa/repository/JpaUserRepository.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/user/adapter/inbound/jpa/repository/JpaUserRepository.java
new file mode 100644
index 0000000..fb1b237
--- /dev/null
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/user/adapter/inbound/jpa/repository/JpaUserRepository.java
@@ -0,0 +1,103 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022-2025 the original author or authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.bernardomg.example.spring.security.ws.basic.user.adapter.inbound.jpa.repository;
+
+import java.util.Collection;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.bernardomg.example.spring.security.ws.basic.user.adapter.inbound.jpa.model.PrivilegeEntity;
+import com.bernardomg.example.spring.security.ws.basic.user.adapter.inbound.jpa.model.RoleEntity;
+import com.bernardomg.example.spring.security.ws.basic.user.adapter.inbound.jpa.model.UserEntity;
+import com.bernardomg.example.spring.security.ws.basic.user.domain.model.Privilege;
+import com.bernardomg.example.spring.security.ws.basic.user.domain.model.User;
+import com.bernardomg.example.spring.security.ws.basic.user.domain.repository.UserRepository;
+
+/**
+ * JPA implementation of the user repository.
+ *
+ * @author Bernardo Martínez Garrido
+ */
+@Repository
+@Transactional
+public final class JpaUserRepository implements UserRepository {
+
+ private final UserSpringRepository userSpringRepository;
+
+ public JpaUserRepository(final UserSpringRepository userSpringRepo) {
+ super();
+
+ userSpringRepository = Objects.requireNonNull(userSpringRepo, "Received a null pointer as user repository");
+ }
+
+ @Override
+ public final Collection
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,13 +22,13 @@
* SOFTWARE.
*/
-package com.bernardomg.example.spring.security.ws.basic.security.user.persistence.repository;
+package com.bernardomg.example.spring.security.ws.basic.user.adapter.inbound.jpa.repository;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
-import com.bernardomg.example.spring.security.ws.basic.security.user.persistence.model.PersistentUser;
+import com.bernardomg.example.spring.security.ws.basic.user.adapter.inbound.jpa.model.UserEntity;
/**
* Repository for users.
@@ -36,16 +36,7 @@
* @author Bernardo Martínez Garrido
*
*/
-public interface UserRepository extends JpaRepository
- * Copyright (c) 2022 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
*/
/**
- * Login model.
+ * JPA user repositories.
*/
-package com.bernardomg.example.spring.security.ws.basic.login.adapter.outbound.rest.controller;
+package com.bernardomg.example.spring.security.ws.basic.user.adapter.inbound.jpa.repository;
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/login/domain/model/LoginStatus.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/user/domain/model/Privilege.java
similarity index 83%
rename from src/main/java/com/bernardomg/example/spring/security/ws/basic/login/domain/model/LoginStatus.java
rename to src/main/java/com/bernardomg/example/spring/security/ws/basic/user/domain/model/Privilege.java
index b2857dd..b119ac2 100644
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/login/domain/model/LoginStatus.java
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/user/domain/model/Privilege.java
@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
- * Copyright (c) 2022 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,14 +22,14 @@
* SOFTWARE.
*/
-package com.bernardomg.example.spring.security.ws.basic.login.domain.model;
+package com.bernardomg.example.spring.security.ws.basic.user.domain.model;
/**
- * Status after a login attempt.
+ * Privilege.
*
* @author Bernardo Martínez Garrido
*
*/
-public record LoginStatus(String username, Boolean logged, String token) {
+public record Privilege(String name) {
}
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/service/package-info.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/user/domain/model/User.java
similarity index 71%
rename from src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/service/package-info.java
rename to src/main/java/com/bernardomg/example/spring/security/ws/basic/user/domain/model/User.java
index 0792da5..f3b2849 100644
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/service/package-info.java
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/user/domain/model/User.java
@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,11 +22,20 @@
* SOFTWARE.
*/
+package com.bernardomg.example.spring.security.ws.basic.user.domain.model;
+
+import java.util.Collection;
+
+import lombok.Builder;
+
/**
- * Services.
- *
- * While in the MVC architecture all the logic seems to be contained inside the controllers, using an additional layer
- * of services helps to isolate all the important logic in the application.
+ * User.
+ *
+ * @author Bernardo Martínez Garrido
+ *
*/
+@Builder(setterPrefix = "with")
+public record User(String email, String username, String name, boolean enabled, boolean expired, boolean locked,
+ boolean passwordExpired, Collection
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,4 +26,4 @@
* User model.
*/
-package com.bernardomg.example.spring.security.ws.basic.security.user.persistence.model;
+package com.bernardomg.example.spring.security.ws.basic.user.domain.model;
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/model/ExampleEntity.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/user/domain/repository/UserRepository.java
similarity index 58%
rename from src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/model/ExampleEntity.java
rename to src/main/java/com/bernardomg/example/spring/security/ws/basic/user/domain/repository/UserRepository.java
index a1fe865..903c167 100644
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/domain/entity/model/ExampleEntity.java
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/user/domain/repository/UserRepository.java
@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,45 +22,43 @@
* SOFTWARE.
*/
-package com.bernardomg.example.spring.security.ws.basic.domain.entity.model;
+package com.bernardomg.example.spring.security.ws.basic.user.domain.repository;
+
+import java.util.Collection;
+import java.util.Optional;
+
+import com.bernardomg.example.spring.security.ws.basic.user.domain.model.User;
/**
- * A simple entity to be used as an example.
+ * User repository.
*
* @author Bernardo Martínez Garrido
*/
-public interface ExampleEntity {
-
- /**
- * Returns the identifier assigned to this entity.
- *
- * If no identifier has been assigned yet, then the value is expected to be {@code null} or lower than zero.
- *
- * @return the entity's identifier
- */
- public Long getId();
+public interface UserRepository {
/**
- * Returns the name of the entity.
+ * Returns all the users.
*
- * @return the entity's name
+ * @return the user for the received username
*/
- public String getName();
+ public Collection
- * Copyright (c) 2022-2023 the original author or authors.
+ * Copyright (c) 2022-2025 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,4 +26,4 @@
* User repositories.
*/
-package com.bernardomg.example.spring.security.ws.basic.security.user.persistence.repository;
+package com.bernardomg.example.spring.security.ws.basic.user.domain.repository;
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index e79d2b9..10e5979 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -15,7 +15,4 @@ management:
endpoints:
web:
exposure:
- include: auditevents
- enabled-by-default: false
- auditevents:
- enabled: true
\ No newline at end of file
+ include: auditevents
\ No newline at end of file
diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt
new file mode 100644
index 0000000..db60dac
--- /dev/null
+++ b/src/main/resources/banner.txt
@@ -0,0 +1,9 @@
+ ____ _ _ _ _ _ _ _
+ | _ \ (_) /\ | | | | | | (_) | | (_)
+ | |_) | __ _ ___ _ ___ / \ _ _| |_| |__ ___ _ __ | |_ _ ___ __ _| |_ _ ___ _ __
+ | _ < / _` / __| |/ __| / /\ \| | | | __| '_ \ / _ \ '_ \| __| |/ __/ _` | __| |/ _ \| '_ \
+ | |_) | (_| \__ \ | (__ / ____ \ |_| | |_| | | | __/ | | | |_| | (_| (_| | |_| | (_) | | | |
+ |____/ \__,_|___/_|\___| /_/ \_\__,_|\__|_| |_|\___|_| |_|\__|_|\___\__,_|\__|_|\___/|_| |_|
+
+${application.title} ${application.version}
+Powered by Spring Boot ${spring-boot.version}
diff --git a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/domain/entity/controller/integration/ITExampleEntityControllerSecurityCredentialsExpiredUser.java b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/domain/entity/controller/integration/ITExampleEntityControllerSecurityCredentialsExpiredUser.java
deleted file mode 100644
index 03adc1d..0000000
--- a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/domain/entity/controller/integration/ITExampleEntityControllerSecurityCredentialsExpiredUser.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * The MIT License (MIT)
- *
- * Copyright (c) 2022-2023 the original author or authors.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.bernardomg.example.spring.security.ws.basic.test.domain.entity.controller.integration;
-
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.test.context.jdbc.Sql;
-import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.RequestBuilder;
-import org.springframework.test.web.servlet.ResultActions;
-import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
-import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
-
-import com.bernardomg.example.spring.security.ws.basic.test.config.annotation.MvcIntegrationTest;
-
-@MvcIntegrationTest
-@DisplayName("Example entity controller - security - credentials expired user")
-@Sql({ "/db/queries/user/credentials_expired.sql", "/db/queries/security/default_role.sql" })
-public final class ITExampleEntityControllerSecurityCredentialsExpiredUser {
-
- @Autowired
- private MockMvc mockMvc;
-
- public ITExampleEntityControllerSecurityCredentialsExpiredUser() {
- super();
- }
-
- @Test
- @DisplayName("An authenticated request is not authorized")
- public final void testGet_authenticated_notAuthorized() throws Exception {
- final ResultActions result;
-
- result = mockMvc.perform(getRequestAuthorized());
-
- // The operation was accepted
- result.andExpect(MockMvcResultMatchers.status()
- .isUnauthorized());
- }
-
- private final RequestBuilder getRequestAuthorized() {
- return MockMvcRequestBuilders.get("/rest/entity")
- .header("Authorization", "Basic YWRtaW46MTIzNA==");
- }
-
-}
diff --git a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/domain/entity/controller/integration/ITExampleEntityControllerSecurityDisabledUser.java b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/domain/entity/controller/integration/ITExampleEntityControllerSecurityDisabledUser.java
deleted file mode 100644
index e47b313..0000000
--- a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/domain/entity/controller/integration/ITExampleEntityControllerSecurityDisabledUser.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * The MIT License (MIT)
- *
- * Copyright (c) 2022-2023 the original author or authors.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.bernardomg.example.spring.security.ws.basic.test.domain.entity.controller.integration;
-
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.test.context.jdbc.Sql;
-import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.RequestBuilder;
-import org.springframework.test.web.servlet.ResultActions;
-import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
-import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
-
-import com.bernardomg.example.spring.security.ws.basic.test.config.annotation.MvcIntegrationTest;
-
-@MvcIntegrationTest
-@DisplayName("Example entity controller - security - disabled user")
-@Sql({ "/db/queries/user/disabled.sql", "/db/queries/security/default_role.sql" })
-public final class ITExampleEntityControllerSecurityDisabledUser {
-
- @Autowired
- private MockMvc mockMvc;
-
- public ITExampleEntityControllerSecurityDisabledUser() {
- super();
- }
-
- @Test
- @DisplayName("An authenticated request is not authorized")
- public final void testGet_authenticated_notAuthorized() throws Exception {
- final ResultActions result;
-
- result = mockMvc.perform(getRequestAuthorized());
-
- // The operation was accepted
- result.andExpect(MockMvcResultMatchers.status()
- .isUnauthorized());
- }
-
- private final RequestBuilder getRequestAuthorized() {
- return MockMvcRequestBuilders.get("/rest/entity")
- .header("Authorization", "Basic YWRtaW46MTIzNA==");
- }
-
-}
diff --git a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/domain/entity/controller/integration/ITExampleEntityControllerSecurityExpiredUser.java b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/domain/entity/controller/integration/ITExampleEntityControllerSecurityExpiredUser.java
deleted file mode 100644
index ae72403..0000000
--- a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/domain/entity/controller/integration/ITExampleEntityControllerSecurityExpiredUser.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * The MIT License (MIT)
- *
- * Copyright (c) 2022-2023 the original author or authors.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.bernardomg.example.spring.security.ws.basic.test.domain.entity.controller.integration;
-
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.test.context.jdbc.Sql;
-import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.RequestBuilder;
-import org.springframework.test.web.servlet.ResultActions;
-import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
-import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
-
-import com.bernardomg.example.spring.security.ws.basic.test.config.annotation.MvcIntegrationTest;
-
-@MvcIntegrationTest
-@DisplayName("Example entity controller - security - expired user")
-@Sql({ "/db/queries/user/expired.sql", "/db/queries/security/default_role.sql" })
-public final class ITExampleEntityControllerSecurityExpiredUser {
-
- @Autowired
- private MockMvc mockMvc;
-
- public ITExampleEntityControllerSecurityExpiredUser() {
- super();
- }
-
- @Test
- @DisplayName("An authenticated request is not authorized")
- public final void testGet_authenticated_notAuthorized() throws Exception {
- final ResultActions result;
-
- result = mockMvc.perform(getRequestAuthorized());
-
- // The operation was accepted
- result.andExpect(MockMvcResultMatchers.status()
- .isUnauthorized());
- }
-
- private final RequestBuilder getRequestAuthorized() {
- return MockMvcRequestBuilders.get("/rest/entity")
- .header("Authorization", "Basic YWRtaW46MTIzNA==");
- }
-
-}
diff --git a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/domain/entity/controller/integration/ITExampleEntityControllerSecurityLockedUser.java b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/domain/entity/controller/integration/ITExampleEntityControllerSecurityLockedUser.java
deleted file mode 100644
index b3600f5..0000000
--- a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/domain/entity/controller/integration/ITExampleEntityControllerSecurityLockedUser.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * The MIT License (MIT)
- *
- * Copyright (c) 2022-2023 the original author or authors.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.bernardomg.example.spring.security.ws.basic.test.domain.entity.controller.integration;
-
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.test.context.jdbc.Sql;
-import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.RequestBuilder;
-import org.springframework.test.web.servlet.ResultActions;
-import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
-import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
-
-import com.bernardomg.example.spring.security.ws.basic.test.config.annotation.MvcIntegrationTest;
-
-@MvcIntegrationTest
-@DisplayName("Example entity controller - security - locked user")
-@Sql({ "/db/queries/user/locked.sql", "/db/queries/security/default_role.sql" })
-public final class ITExampleEntityControllerSecurityLockedUser {
-
- @Autowired
- private MockMvc mockMvc;
-
- public ITExampleEntityControllerSecurityLockedUser() {
- super();
- }
-
- @Test
- @DisplayName("An authenticated request is not authorized")
- public final void testGet_authenticated_notAuthorized() throws Exception {
- final ResultActions result;
-
- result = mockMvc.perform(getRequestAuthorized());
-
- // The operation was accepted
- result.andExpect(MockMvcResultMatchers.status()
- .isUnauthorized());
- }
-
- private final RequestBuilder getRequestAuthorized() {
- return MockMvcRequestBuilders.get("/rest/entity")
- .header("Authorization", "Basic YWRtaW46MTIzNA==");
- }
-
-}
diff --git a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/login/adapter/outbound/rest/controller/integration/ITLoginControllerSecurity.java b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/login/adapter/outbound/rest/controller/integration/ITLoginControllerSecurity.java
deleted file mode 100644
index dcd83ea..0000000
--- a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/login/adapter/outbound/rest/controller/integration/ITLoginControllerSecurity.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * The MIT License (MIT)
- *
- * Copyright (c) 2022 the original author or authors.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.bernardomg.example.spring.security.ws.basic.test.login.adapter.outbound.rest.controller.integration;
-
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.MediaType;
-import org.springframework.test.context.jdbc.Sql;
-import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.RequestBuilder;
-import org.springframework.test.web.servlet.ResultActions;
-import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
-import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
-
-import com.bernardomg.example.spring.security.ws.basic.test.config.annotation.MvcIntegrationTest;
-
-@MvcIntegrationTest
-@DisplayName("Login controller - security")
-@Sql({ "/db/queries/user/single.sql", "/db/queries/security/default_role.sql" })
-public final class ITLoginControllerSecurity {
-
- @Autowired
- private MockMvc mockMvc;
-
- public ITLoginControllerSecurity() {
- super();
- }
-
- @Test
- @DisplayName("Accepts unauthenticated requests")
- public final void testGet_unauthorized() throws Exception {
- final ResultActions result;
-
- result = mockMvc.perform(getRequest());
-
- // The operation was accepted
- result.andExpect(MockMvcResultMatchers.status()
- .isOk());
- }
-
- private final RequestBuilder getRequest() {
- return MockMvcRequestBuilders.post("/login")
- .contentType(MediaType.APPLICATION_JSON)
- .content("{ \"username\":\"admin\", \"password\":\"1234\" }");
- }
-
-}
diff --git a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/login/usecase/service/unit/ITLoginService.java b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/login/usecase/service/unit/ITLoginService.java
deleted file mode 100644
index 206032e..0000000
--- a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/login/usecase/service/unit/ITLoginService.java
+++ /dev/null
@@ -1,67 +0,0 @@
-
-package com.bernardomg.example.spring.security.ws.basic.test.login.usecase.service.unit;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.test.context.jdbc.Sql;
-
-import com.bernardomg.example.spring.security.ws.basic.login.domain.model.LoginStatus;
-import com.bernardomg.example.spring.security.ws.basic.login.usecase.service.LoginService;
-import com.bernardomg.example.spring.security.ws.basic.test.config.annotation.IntegrationTest;
-
-@IntegrationTest
-@DisplayName("Login service")
-@Sql({ "/db/queries/user/single.sql", "/db/queries/security/default_role.sql" })
-public class ITLoginService {
-
- @Autowired
- private LoginService service;
-
- public ITLoginService() {
- super();
- }
-
- @Test
- @DisplayName("An existing user with invalid password doesn't log in")
- public final void testLogin_invalidPassword() {
- final LoginStatus result;
-
- result = service.login("admin", "abc");
-
- Assertions.assertFalse(result.logged());
- }
-
- @Test
- @DisplayName("A not existing user doesn't log in")
- public final void testLogin_notExisting() {
- final LoginStatus result;
-
- result = service.login("abc", "1234");
-
- Assertions.assertFalse(result.logged());
- }
-
- @Test
- @DisplayName("An existing user with valid password logs in")
- public final void testLogin_valid() {
- final LoginStatus result;
-
- result = service.login("admin", "1234");
-
- Assertions.assertTrue(result.logged());
- }
-
- @Test
- @DisplayName("A valid login returns all the data")
- public final void testLogin_valid_data() {
- final LoginStatus result;
-
- result = service.login("admin", "1234");
-
- Assertions.assertEquals("admin", result.username());
- Assertions.assertEquals("YWRtaW46MTIzNA==", result.token());
- }
-
-}
diff --git a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/login/usecase/service/unit/ITLoginServiceNoData.java b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/login/usecase/service/unit/ITLoginServiceNoData.java
deleted file mode 100644
index 4212122..0000000
--- a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/login/usecase/service/unit/ITLoginServiceNoData.java
+++ /dev/null
@@ -1,34 +0,0 @@
-
-package com.bernardomg.example.spring.security.ws.basic.test.login.usecase.service.unit;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-
-import com.bernardomg.example.spring.security.ws.basic.login.domain.model.LoginStatus;
-import com.bernardomg.example.spring.security.ws.basic.login.usecase.service.LoginService;
-import com.bernardomg.example.spring.security.ws.basic.test.config.annotation.IntegrationTest;
-
-@IntegrationTest
-@DisplayName("Login service - no data")
-public class ITLoginServiceNoData {
-
- @Autowired
- private LoginService service;
-
- public ITLoginServiceNoData() {
- super();
- }
-
- @Test
- @DisplayName("Trying to log in returns a user which isn't logged in")
- public final void testLogin_invalidPassword() {
- final LoginStatus result;
-
- result = service.login("admin", "abc");
-
- Assertions.assertFalse(result.logged());
- }
-
-}
diff --git a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/login/usecase/service/unit/ITLoginServiceNoPrivileges.java b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/login/usecase/service/unit/ITLoginServiceNoPrivileges.java
deleted file mode 100644
index 9b16c3f..0000000
--- a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/login/usecase/service/unit/ITLoginServiceNoPrivileges.java
+++ /dev/null
@@ -1,36 +0,0 @@
-
-package com.bernardomg.example.spring.security.ws.basic.test.login.usecase.service.unit;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.test.context.jdbc.Sql;
-
-import com.bernardomg.example.spring.security.ws.basic.login.domain.model.LoginStatus;
-import com.bernardomg.example.spring.security.ws.basic.login.usecase.service.LoginService;
-import com.bernardomg.example.spring.security.ws.basic.test.config.annotation.IntegrationTest;
-
-@IntegrationTest
-@DisplayName("Login service - no privileges")
-@Sql({ "/db/queries/user/single.sql", "/db/queries/security/default_role_no_privileges.sql" })
-public class ITLoginServiceNoPrivileges {
-
- @Autowired
- private LoginService service;
-
- public ITLoginServiceNoPrivileges() {
- super();
- }
-
- @Test
- @DisplayName("An existing user can't log in")
- public final void testLogin_valid() {
- final LoginStatus result;
-
- result = service.login("admin", "1234");
-
- Assertions.assertFalse(result.logged());
- }
-
-}
diff --git a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/domain/entity/controller/integration/ITExampleEntityControllerSecurity.java b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/person/adapter/outbound/rest/controller/integration/ITPersonControllerSecurity.java
similarity index 53%
rename from src/test/java/com/bernardomg/example/spring/security/ws/basic/test/domain/entity/controller/integration/ITExampleEntityControllerSecurity.java
rename to src/test/java/com/bernardomg/example/spring/security/ws/basic/test/person/adapter/outbound/rest/controller/integration/ITPersonControllerSecurity.java
index f106edb..bbf39cd 100644
--- a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/domain/entity/controller/integration/ITExampleEntityControllerSecurity.java
+++ b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/person/adapter/outbound/rest/controller/integration/ITPersonControllerSecurity.java
@@ -22,12 +22,11 @@
* SOFTWARE.
*/
-package com.bernardomg.example.spring.security.ws.basic.test.domain.entity.controller.integration;
+package com.bernardomg.example.spring.security.ws.basic.test.person.adapter.outbound.rest.controller.integration;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.ResultActions;
@@ -35,22 +34,33 @@
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import com.bernardomg.example.spring.security.ws.basic.test.config.annotation.MvcIntegrationTest;
+import com.bernardomg.example.spring.security.ws.basic.test.security.user.config.CredentialsExpiredUser;
+import com.bernardomg.example.spring.security.ws.basic.test.security.user.config.DisabledUser;
+import com.bernardomg.example.spring.security.ws.basic.test.security.user.config.LockedUser;
+import com.bernardomg.example.spring.security.ws.basic.test.security.user.config.ValidUser;
@MvcIntegrationTest
@DisplayName("Example entity controller - security")
-@Sql({ "/db/queries/user/single.sql", "/db/queries/security/default_role.sql" })
-public final class ITExampleEntityControllerSecurity {
+final class ITPersonControllerSecurity {
+
+ private static final String ROUTE = "/person";
@Autowired
- private MockMvc mockMvc;
+ private MockMvc mockMvc;
- public ITExampleEntityControllerSecurity() {
- super();
+ private final RequestBuilder getRequest() {
+ return MockMvcRequestBuilders.get(ROUTE);
+ }
+
+ private final RequestBuilder getRequestAuthorized() {
+ return MockMvcRequestBuilders.get(ROUTE)
+ .header("Authorization", "Basic YWRtaW46MTIzNA==");
}
@Test
@DisplayName("An authenticated request is authorized")
- public final void testGet_authorized() throws Exception {
+ @ValidUser
+ void testGet_authorized() throws Exception {
final ResultActions result;
result = mockMvc.perform(getRequestAuthorized());
@@ -61,24 +71,68 @@ public final void testGet_authorized() throws Exception {
}
@Test
- @DisplayName("A not authenticated request is not authorized")
- public final void testGet_unauthorized() throws Exception {
+ @DisplayName("A locked user is not authorized")
+ @CredentialsExpiredUser
+ void testGet_credentialsExpired() throws Exception {
final ResultActions result;
- result = mockMvc.perform(getRequest());
+ result = mockMvc.perform(getRequestAuthorized());
// The operation was accepted
result.andExpect(MockMvcResultMatchers.status()
.isUnauthorized());
}
- private final RequestBuilder getRequest() {
- return MockMvcRequestBuilders.get("/rest/entity");
+ @Test
+ @DisplayName("An expired user is not authorized")
+ @DisabledUser
+ void testGet_expired() throws Exception {
+ final ResultActions result;
+
+ result = mockMvc.perform(getRequestAuthorized());
+
+ // The operation was accepted
+ result.andExpect(MockMvcResultMatchers.status()
+ .isUnauthorized());
}
- private final RequestBuilder getRequestAuthorized() {
- return MockMvcRequestBuilders.get("/rest/entity")
- .header("Authorization", "Basic YWRtaW46MTIzNA==");
+ @Test
+ @DisplayName("A locked user is not authorized")
+ @LockedUser
+ void testGet_locked() throws Exception {
+ final ResultActions result;
+
+ result = mockMvc.perform(getRequestAuthorized());
+
+ // The operation was accepted
+ result.andExpect(MockMvcResultMatchers.status()
+ .isUnauthorized());
+ }
+
+ @Test
+ @DisplayName("A disabled user is not authorized")
+ @DisabledUser
+ void testGet_notAuthorized() throws Exception {
+ final ResultActions result;
+
+ result = mockMvc.perform(getRequestAuthorized());
+
+ // The operation was accepted
+ result.andExpect(MockMvcResultMatchers.status()
+ .isUnauthorized());
+ }
+
+ @Test
+ @DisplayName("A not authenticated request is not authorized")
+ @ValidUser
+ void testGet_unauthorized() throws Exception {
+ final ResultActions result;
+
+ result = mockMvc.perform(getRequest());
+
+ // The operation was accepted
+ result.andExpect(MockMvcResultMatchers.status()
+ .isUnauthorized());
}
}
diff --git a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/CredentialsExpiredUser.java b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/CredentialsExpiredUser.java
new file mode 100644
index 0000000..a06498d
--- /dev/null
+++ b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/CredentialsExpiredUser.java
@@ -0,0 +1,20 @@
+
+package com.bernardomg.example.spring.security.ws.basic.test.security.user.config;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.test.context.jdbc.Sql;
+
+@Sql({ "/db/queries/user/credentials_expired.sql", "/db/queries/security/default_role.sql" })
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface CredentialsExpiredUser {
+
+}
diff --git a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/DisabledUser.java b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/DisabledUser.java
new file mode 100644
index 0000000..0038488
--- /dev/null
+++ b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/DisabledUser.java
@@ -0,0 +1,20 @@
+
+package com.bernardomg.example.spring.security.ws.basic.test.security.user.config;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.test.context.jdbc.Sql;
+
+@Sql({ "/db/queries/user/disabled.sql", "/db/queries/security/default_role.sql" })
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface DisabledUser {
+
+}
diff --git a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/ExpiredUser.java b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/ExpiredUser.java
new file mode 100644
index 0000000..78048e4
--- /dev/null
+++ b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/ExpiredUser.java
@@ -0,0 +1,20 @@
+
+package com.bernardomg.example.spring.security.ws.basic.test.security.user.config;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.test.context.jdbc.Sql;
+
+@Sql({ "/db/queries/user/expired.sql", "/db/queries/security/default_role.sql" })
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface ExpiredUser {
+
+}
diff --git a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/LockedUser.java b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/LockedUser.java
new file mode 100644
index 0000000..4eec58c
--- /dev/null
+++ b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/LockedUser.java
@@ -0,0 +1,20 @@
+
+package com.bernardomg.example.spring.security.ws.basic.test.security.user.config;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.test.context.jdbc.Sql;
+
+@Sql({ "/db/queries/user/locked.sql", "/db/queries/security/default_role.sql" })
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface LockedUser {
+
+}
diff --git a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/UserWithoutPermissions.java b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/UserWithoutPermissions.java
new file mode 100644
index 0000000..f28c449
--- /dev/null
+++ b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/UserWithoutPermissions.java
@@ -0,0 +1,20 @@
+
+package com.bernardomg.example.spring.security.ws.basic.test.security.user.config;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.test.context.jdbc.Sql;
+
+@Sql({ "/db/queries/user/single.sql" })
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface UserWithoutPermissions {
+
+}
diff --git a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/ValidUser.java b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/ValidUser.java
new file mode 100644
index 0000000..f221993
--- /dev/null
+++ b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/config/ValidUser.java
@@ -0,0 +1,20 @@
+
+package com.bernardomg.example.spring.security.ws.basic.test.security.user.config;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.test.context.jdbc.Sql;
+
+@Sql({ "/db/queries/user/single.sql", "/db/queries/security/default_role.sql" })
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface ValidUser {
+
+}
diff --git a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/persistence/repository/integration/ITPrivilegeRepository.java b/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/persistence/repository/integration/ITPrivilegeRepository.java
deleted file mode 100644
index cec8fe7..0000000
--- a/src/test/java/com/bernardomg/example/spring/security/ws/basic/test/security/user/persistence/repository/integration/ITPrivilegeRepository.java
+++ /dev/null
@@ -1,67 +0,0 @@
-
-package com.bernardomg.example.spring.security.ws.basic.test.security.user.persistence.repository.integration;
-
-import java.util.Collection;
-import java.util.stream.Collectors;
-
-import org.apache.commons.collections4.IterableUtils;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.test.context.jdbc.Sql;
-
-import com.bernardomg.example.spring.security.ws.basic.security.user.persistence.model.PersistentPrivilege;
-import com.bernardomg.example.spring.security.ws.basic.security.user.persistence.repository.PrivilegeRepository;
-import com.bernardomg.example.spring.security.ws.basic.test.config.annotation.IntegrationTest;
-
-@IntegrationTest
-@DisplayName("Privilege repository")
-@Sql({ "/db/queries/user/single.sql", "/db/queries/security/default_role.sql" })
-public class ITPrivilegeRepository {
-
- @Autowired
- private PrivilegeRepository repository;
-
- public ITPrivilegeRepository() {
- super();
- }
-
- @Test
- @DisplayName("Returns all the privileges for a user")
- public void testFindForUser_Count() {
- final IterableGranted authorities
- * Exceptions
- *
- *
- *
- * @author Bernardo Martínez Garrido
- *
- */
-@Slf4j
-public final class PersistentUserDetailsService implements UserDetailsService {
-
- /**
- * Repository for the privileges.
- */
- private final PrivilegeRepository privilegeRepo;
-
- /**
- * Repository for the user data.
- */
- private final UserRepository userRepo;
-
- /**
- * Constructs a user details service.
- *
- * @param userRepository
- * repository for user details
- * @param privilegeRepository
- * repository for privileges
- */
- public PersistentUserDetailsService(final UserRepository userRepository,
- final PrivilegeRepository privilegeRepository) {
- super();
-
- userRepo = Objects.requireNonNull(userRepository, "Received a null pointer as repository");
- privilegeRepo = Objects.requireNonNull(privilegeRepository, "Received a null pointer as repository");
- }
-
- @Override
- public final UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
- final OptionalGranted authorities
+ * Exceptions
+ *
+ *
+ *
+ * @author Bernardo Martínez Garrido
+ *
+ */
+@Slf4j
+public final class UserDomainDetailsService implements UserDetailsService {
+
+ /**
+ * User repository.
+ */
+ private final UserRepository userRepository;
+
+ /**
+ * Constructs a user details service.
+ *
+ * @param userRepo
+ * users repository
+ */
+ public UserDomainDetailsService(final UserRepository userRepo) {
+ super();
+
+ userRepository = Objects.requireNonNull(userRepo, "Received a null pointer as user repository");
+ }
+
+ @Override
+ public final UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
+ final User user;
+ final UserDetails details;
+ final String password;
+
+ user = userRepository.findOne(username.toLowerCase(Locale.getDefault()))
+ .orElseThrow(() -> {
+ log.error("Username {} not found in database", username);
+ throw new UsernameNotFoundException(String.format("Username %s not found in database", username));
+ });
+
+ if (user.privileges()
+ .isEmpty()) {
+ log.error("Username {} has no authorities", username);
+ throw new UsernameNotFoundException(String.format("Username %s has no authorities", username));
+ }
+
+ password = userRepository.findPassword(username)
+ .get();
+ details = toUserDetails(user, password);
+
+ log.debug("User {} exists. Enabled: {}. Non expired: {}. Non locked: {}. Credentials non expired: {}", username,
+ details.isEnabled(), details.isAccountNonExpired(), details.isAccountNonLocked(),
+ details.isCredentialsNonExpired());
+ log.debug("Authorities for {}: {}", username, details.getAuthorities());
+
+ return details;
+ }
+
+ /**
+ * Creates a {@link GrantedAuthority} from the {@link Privilege}.
+ *
+ * @param privilege
+ * privilege to transform
+ * @return {@code GrantedAuthority} from the {@code Privilege}
+ */
+ private final GrantedAuthority toGrantedAuthority(final Privilege privilege) {
+ return new SimpleGrantedAuthority(privilege.name());
+ }
+
+ /**
+ * Transforms a user into a user details object.
+ *
+ * @param user
+ * user to transform
+ * @param password
+ * user password
+ * @return equivalent user details
+ */
+ private final UserDetails toUserDetails(final User user, final String password) {
+ final Boolean enabled;
+ final Boolean accountNonExpired;
+ final Boolean credentialsNonExpired;
+ final Boolean accountNonLocked;
+ final Collection extends GrantedAuthority> authorities;
+
+ // Loads status
+ enabled = user.enabled();
+ accountNonExpired = !user.expired();
+ credentialsNonExpired = !user.passwordExpired();
+ accountNonLocked = !user.locked();
+
+ // Authorities
+ authorities = user.privileges()
+ .stream()
+ .map(this::toGrantedAuthority)
+ .toList();
+
+ return new org.springframework.security.core.userdetails.User(user.username(), password, enabled,
+ accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
+ }
+
+}
diff --git a/src/main/java/com/bernardomg/example/spring/security/ws/basic/security/userdetails/package-info.java b/src/main/java/com/bernardomg/example/spring/security/ws/basic/springframework/userdetails/package-info.java
similarity index 88%
rename from src/main/java/com/bernardomg/example/spring/security/ws/basic/security/userdetails/package-info.java
rename to src/main/java/com/bernardomg/example/spring/security/ws/basic/springframework/userdetails/package-info.java
index a12ce4f..3ea1383 100644
--- a/src/main/java/com/bernardomg/example/spring/security/ws/basic/security/userdetails/package-info.java
+++ b/src/main/java/com/bernardomg/example/spring/security/ws/basic/springframework/userdetails/package-info.java
@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*