From 1bebb005afdffa5fcdd54b217a3f8bff39a39c1c Mon Sep 17 00:00:00 2001 From: "Mantena, Ravi (rx908f)" Date: Thu, 3 Sep 2020 17:14:41 -0400 Subject: New Auth Service in Mod2 Issue-ID: DCAEGEN2-2317 Change-Id: I34b08d7731cc23028f469376ef2147bb28a28b7f Signed-off-by: Ravi Mantena --- mod2/auth-service/Dockerfile | 11 ++ mod2/auth-service/pom.xml | 171 +++++++++++++++++++++ .../platform/mod/AuthServiceApplication.java | 40 +++++ .../org/onap/dcaegen2/platform/mod/DataLoader.java | 97 ++++++++++++ .../platform/mod/controllers/AuthController.java | 171 +++++++++++++++++++++ .../platform/mod/controllers/RoleController.java | 58 +++++++ .../platform/mod/controllers/UserController.java | 96 ++++++++++++ .../mod/exceptions/AppExceptionHandler.java | 52 +++++++ .../exceptions/IllegalUserOperationException.java | 34 ++++ .../mod/exceptions/RoleNotExistsException.java | 34 ++++ .../mod/exceptions/UserAlreadyExistsException.java | 34 ++++ .../mod/exceptions/UserNotFoundException.java | 34 ++++ .../platform/mod/models/GenericResponse.java | 40 +++++ .../dcaegen2/platform/mod/models/JwtResponse.java | 50 ++++++ .../dcaegen2/platform/mod/models/LoginRequest.java | 43 ++++++ .../onap/dcaegen2/platform/mod/models/ModUser.java | 75 +++++++++ .../onap/dcaegen2/platform/mod/models/Role.java | 50 ++++++ .../platform/mod/models/SignupRequest.java | 53 +++++++ .../platform/mod/models/UpdateUserRequest.java | 47 ++++++ .../platform/mod/repositories/RoleRepository.java | 37 +++++ .../platform/mod/repositories/UserRepository.java | 40 +++++ .../mod/security/WebSecurityConfigurer.java | 92 +++++++++++ .../mod/security/jwt/AuthEntryPointJwt.java | 51 ++++++ .../platform/mod/security/jwt/AuthTokenFilter.java | 81 ++++++++++ .../platform/mod/security/jwt/JwtUtils.java | 90 +++++++++++ .../mod/security/services/UserDetailsImpl.java | 127 +++++++++++++++ .../security/services/UserDetailsServiceImpl.java | 100 ++++++++++++ .../mod/services/MODUserDetailService.java | 56 +++++++ .../src/main/resources/application.properties | 32 ++++ .../mod/objectmothers/AuthObjectMother.java | 85 ++++++++++ .../mod/objectmothers/RoleObjectMother.java | 56 +++++++ .../mod/objectmothers/UserObjectMother.java | 100 ++++++++++++ .../onap/dcaegen2/platform/mod/util/TestUtil.java | 60 ++++++++ .../platform/mod/web/AuthControllerTest.java | 149 ++++++++++++++++++ .../platform/mod/web/RoleControllerTest.java | 109 +++++++++++++ .../platform/mod/web/UserControllerTest.java | 168 ++++++++++++++++++++ .../src/test/resources/application.properties | 1 + .../resources/http/requests/AuthLoginRequest.json | 4 + .../resources/http/requests/AuthSignupRequest.json | 6 + .../componentSpec_hello_world-with-dmaap.json | 149 ++++++++++++++++++ .../specification/policy_json_sample_3.json | 28 ++++ 41 files changed, 2811 insertions(+) create mode 100644 mod2/auth-service/Dockerfile create mode 100644 mod2/auth-service/pom.xml create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/AuthServiceApplication.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/DataLoader.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/AuthController.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/RoleController.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/UserController.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/AppExceptionHandler.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/IllegalUserOperationException.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/RoleNotExistsException.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/UserAlreadyExistsException.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/UserNotFoundException.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/GenericResponse.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/JwtResponse.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/LoginRequest.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/ModUser.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/Role.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/SignupRequest.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/UpdateUserRequest.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/repositories/RoleRepository.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/repositories/UserRepository.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/WebSecurityConfigurer.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/AuthEntryPointJwt.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/AuthTokenFilter.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/JwtUtils.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/services/UserDetailsImpl.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/services/UserDetailsServiceImpl.java create mode 100644 mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/services/MODUserDetailService.java create mode 100644 mod2/auth-service/src/main/resources/application.properties create mode 100644 mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/AuthObjectMother.java create mode 100644 mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/RoleObjectMother.java create mode 100644 mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/UserObjectMother.java create mode 100644 mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/util/TestUtil.java create mode 100644 mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/AuthControllerTest.java create mode 100644 mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/RoleControllerTest.java create mode 100644 mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/UserControllerTest.java create mode 100644 mod2/auth-service/src/test/resources/application.properties create mode 100644 mod2/auth-service/src/test/resources/http/requests/AuthLoginRequest.json create mode 100644 mod2/auth-service/src/test/resources/http/requests/AuthSignupRequest.json create mode 100644 mod2/auth-service/src/test/resources/specification/componentSpec_hello_world-with-dmaap.json create mode 100644 mod2/auth-service/src/test/resources/specification/policy_json_sample_3.json diff --git a/mod2/auth-service/Dockerfile b/mod2/auth-service/Dockerfile new file mode 100644 index 0000000..c427bda --- /dev/null +++ b/mod2/auth-service/Dockerfile @@ -0,0 +1,11 @@ +FROM onap/integration-java11:7.1.0 +WORKDIR /usr/app +VOLUME /tmp + +ADD target/auth-service-1.0.0-SNAPSHOT.jar auth-service-1.0.0-SNAPSHOT.jar + +EXPOSE 8082 + +ENTRYPOINT ["java", \ + "-Djava.security.egd=file:/dev/./urandom", \ + "-jar", "auth-service-1.0.0-SNAPSHOT.jar"] \ No newline at end of file diff --git a/mod2/auth-service/pom.xml b/mod2/auth-service/pom.xml new file mode 100644 index 0000000..1fd4f02 --- /dev/null +++ b/mod2/auth-service/pom.xml @@ -0,0 +1,171 @@ + + + + + 4.0.0 + + org.onap.oparent + oparent + 2.0.0 + + org.onap.dcaegen2.platform.mod + auth-service + 1.0.0-SNAPSHOT + auth-service + REST APIs to serve Auth Service + + + 11 + ${java.version} + ${java.version} + + + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + org.springframework.boot + spring-boot-starter-data-mongodb-reactive + + + com.google.code.gson + gson + 2.8.6 + + + org.springframework.boot + spring-boot-starter-security + + + io.jsonwebtoken + jjwt + 0.9.1 + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-webflux + + + org.springframework.boot + spring-boot-starter-validation + + + + org.projectlombok + lombok + + + com.squareup.okhttp3 + okhttp + 4.0.1 + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + org.springframework.security + spring-security-test + test + + + com.squareup.okhttp3 + mockwebserver + 4.0.1 + test + + + org.springframework.security + spring-security-test + test + + + io.projectreactor + reactor-test + test + + + javax.xml.bind + jaxb-api + 2.3.1 + + + org.testng + testng + RELEASE + test + + + + + + + + org.springframework.boot + spring-boot-dependencies + 2.2.5.RELEASE + pom + import + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.2.5.RELEASE + + + + repackage + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + + diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/AuthServiceApplication.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/AuthServiceApplication.java new file mode 100644 index 0000000..5b147bf --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/AuthServiceApplication.java @@ -0,0 +1,40 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author + * @date 09/08/2020 + * Auth Service Application + */ +@SpringBootApplication +public class AuthServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(AuthServiceApplication.class, args); + } + +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/DataLoader.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/DataLoader.java new file mode 100644 index 0000000..959b450 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/DataLoader.java @@ -0,0 +1,97 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod; + +import org.onap.dcaegen2.platform.mod.models.ModUser; +import org.onap.dcaegen2.platform.mod.models.Role; +import org.onap.dcaegen2.platform.mod.repositories.RoleRepository; +import org.onap.dcaegen2.platform.mod.repositories.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +/** + * @author + * @date 09/08/2020 + * To Initialize Roles and create Default Admin User + */ +@Component +public class DataLoader implements ApplicationRunner { + + @Autowired + private RoleRepository roleRepository; + + @Autowired + private UserRepository userRepository; + + @Autowired + PasswordEncoder passwordEncoder; + + @Override + public void run(ApplicationArguments args) throws Exception { + populateRoles(); + populateAdminUser(); + } + + private void populateRoles() { + List roles = createRoles(); + roles.forEach((role) -> { + boolean roleNotPresent = !roleRepository.findByName(role.getName()).isPresent(); + if(roleNotPresent) + roleRepository.save(role); + }); + + } + + private List createRoles() { + Role admin = new Role("ROLE_ADMIN"); + Role user = new Role("ROLE_USER"); + Role developer = new Role("ROLE_DEVELOPER"); + return Arrays.asList(admin, user, developer); + } + + private void populateAdminUser() { + boolean adminNotPresent = !userRepository.findByUsername("admin").isPresent(); + if(adminNotPresent) { + ModUser admin = createAdmin(); + userRepository.save(admin); + } + } + + private ModUser createAdmin() { + ModUser admin = new ModUser(); + admin.setUsername("admin"); + admin.setFullName("Admin"); + admin.setPassword(passwordEncoder.encode("admin@mod")); + HashSet roleAdmin = new HashSet<>(); + roleAdmin.add(roleRepository.findByName("ROLE_ADMIN").get()); + admin.setRoles(roleAdmin); + return admin; + } +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/AuthController.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/AuthController.java new file mode 100644 index 0000000..6612138 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/AuthController.java @@ -0,0 +1,171 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.controllers; + +import org.onap.dcaegen2.platform.mod.exceptions.RoleNotExistsException; +import org.onap.dcaegen2.platform.mod.exceptions.UserAlreadyExistsException; +import org.onap.dcaegen2.platform.mod.models.LoginRequest; +import org.onap.dcaegen2.platform.mod.models.JwtResponse; +import org.onap.dcaegen2.platform.mod.models.SignupRequest; +import org.onap.dcaegen2.platform.mod.models.ModUser; +import org.onap.dcaegen2.platform.mod.models.GenericResponse; +import org.onap.dcaegen2.platform.mod.models.Role; +import org.onap.dcaegen2.platform.mod.repositories.RoleRepository; +import org.onap.dcaegen2.platform.mod.repositories.UserRepository; +import org.onap.dcaegen2.platform.mod.security.jwt.JwtUtils; +import org.onap.dcaegen2.platform.mod.security.services.UserDetailsImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + + +import javax.validation.Valid; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + + +/** + * @author + * @date 09/08/2020 + * Authentication Operations + */ +@RestController +@RequestMapping("/api/auth") +@CrossOrigin(origins = "*") +public class AuthController { + + @Autowired + AuthenticationManager authenticationManager; + + @Autowired + UserRepository userRepository; + + @Autowired + RoleRepository roleRepository; + + @Autowired + PasswordEncoder passwordEncoder; + + @Autowired + JwtUtils jwtUtils; + + @PreAuthorize("isAuthenticated()") + @PostMapping("/validate-token") + public ResponseEntity validateToken() { + return new ResponseEntity("true", HttpStatus.OK); + } + + @PostMapping("/signin") + public ResponseEntity authenticateUser(@RequestBody @Valid LoginRequest loginRequest) { + Authentication authentication = authenticateLoginRequest(loginRequest); + SecurityContextHolder.getContext().setAuthentication(authentication); + String jwt = jwtUtils.generateJwtToken(authentication); + return setUserContext(authentication, jwt); + } + + private Authentication authenticateLoginRequest(@RequestBody @Valid LoginRequest loginRequest) { + return authenticationManager.authenticate( + new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()) + ); + } + + private ResponseEntity setUserContext(Authentication authentication, String jwt) { + UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal(); + List roles = setRolesFromUserDetails(userDetails); + return buildUserContext(jwt, userDetails, roles); + } + + private List setRolesFromUserDetails(UserDetailsImpl userDetails) { + return userDetails.getAuthorities().stream() + .map(item -> ((GrantedAuthority) item).getAuthority()) + .collect(Collectors.toList()); + } + + private ResponseEntity buildUserContext(String jwt, UserDetailsImpl userDetails, List roles) { + return ResponseEntity.ok(JwtResponse.builder() + .id(userDetails.getId()) + .roles(roles) + .username(userDetails.getUsername()) + .token(jwt) + .fullName(userDetails.getFullName()) + .build() + ); + } + + @PreAuthorize("hasRole('ADMIN')") + @PostMapping("/signup") + public ResponseEntity registerUser(@RequestBody @Valid SignupRequest request) { + checkIfUserExists(request); + ModUser user = createNewUser(request); + userRepository.save(user); + return ResponseEntity.ok(new GenericResponse("User registered successfully!")); + } + + private void checkIfUserExists(@RequestBody @Valid SignupRequest signUpRequest) { + if (userRepository.existsByUsername(signUpRequest.getUsername())) + throw new UserAlreadyExistsException("Username already exists!"); + } + + private ModUser createNewUser(@RequestBody @Valid SignupRequest request) { + ModUser user = new ModUser(); + user.setUsername(request.getUsername()); + user.setFullName(request.getFullName()); + user.setPassword(getEncodedPassword(request)); + Set roles = createRoles(request.getRoles()); + user.setRoles(roles); + return user; + } + + private String getEncodedPassword(@RequestBody @Valid SignupRequest request) { + return passwordEncoder.encode(request.getPassword()); + } + + public Set createRoles(Set roleStrings) { + Set roles = new HashSet<>(); + for (String roleStr : roleStrings) { + roles.add(getRole(roleStr)); + } + return roles; + } + + private Role getRole(String roleStr) { + return roleRepository.findByName(roleStr).orElseThrow( + () -> new RoleNotExistsException(String.format("Role %s does not exist", roleStr))); + } +} + + diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/RoleController.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/RoleController.java new file mode 100644 index 0000000..e129cda --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/RoleController.java @@ -0,0 +1,58 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.controllers; + +import org.onap.dcaegen2.platform.mod.repositories.RoleRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.RequestMapping; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author + * @date 09/08/2020 + * Role Operations + */ +@RestController +@RequestMapping("/api/roles") +@CrossOrigin(origins = "*") +public class RoleController { + + @Autowired + RoleRepository roleRepository; + + @GetMapping + @ResponseStatus(HttpStatus.OK) + public List getRoles(){ + return roleRepository.findAll() + .stream() + .map(role -> role.getName()) + .collect(Collectors.toList()); + } +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/UserController.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/UserController.java new file mode 100644 index 0000000..90e7b62 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/UserController.java @@ -0,0 +1,96 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.controllers; + +import org.onap.dcaegen2.platform.mod.exceptions.UserNotFoundException; +import org.onap.dcaegen2.platform.mod.models.GenericResponse; +import org.onap.dcaegen2.platform.mod.models.ModUser; +import org.onap.dcaegen2.platform.mod.models.UpdateUserRequest; +import org.onap.dcaegen2.platform.mod.security.services.UserDetailsServiceImpl; +import org.onap.dcaegen2.platform.mod.services.MODUserDetailService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + + +/** + * @author + * @date 09/08/2020 + * User Operations + */ +@RestController +@RequestMapping("/api/users") +@CrossOrigin(origins = "*") +public class UserController { + + @Autowired + private MODUserDetailService modUserDetailService; + + @Autowired + private UserDetailsServiceImpl userDetailsService; + + @PreAuthorize("hasRole('ADMIN')") + @GetMapping("/getAll") + @ResponseStatus(HttpStatus.OK) + public List getAllUsers() { + return modUserDetailService.findAll(); + } + + @PreAuthorize("hasRole('ADMIN') or hasRole('USER')") + @GetMapping("/{username}") + public UserDetails getUser(@PathVariable String username) { + return userDetailsService.loadUserByUsername(username); + } + + @PreAuthorize("hasRole('ADMIN')") + @PatchMapping("/admin/{username}") + public ModUser adminUpdateUserProfile(@PathVariable String username, @RequestBody @Valid UpdateUserRequest + userRequest, @RequestHeader (name="Authorization") String token) { + return userDetailsService.adminUpdateUser(username, userRequest, token); + } + + @PreAuthorize("hasRole('USER') or hasRole('DEVELOPER')") + @PatchMapping("/user/{username}") + public ModUser userUpdateOwnProfile(@PathVariable String username, @RequestBody @Valid UpdateUserRequest + userRequest, @RequestHeader (name="Authorization") String token) { + return userDetailsService.userUpdateOwnProfile(username, userRequest, token); + } + + @PreAuthorize("hasRole('ADMIN')") + @DeleteMapping("/{username}") + public ResponseEntity deleteUser(@PathVariable String username) { + modUserDetailService.deleteUserByUsername(username); + return ResponseEntity.ok(new GenericResponse("User " + username + " was removed")); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.NOT_FOUND) + public void userNotFoundHandler(UserNotFoundException ex) { + } +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/AppExceptionHandler.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/AppExceptionHandler.java new file mode 100644 index 0000000..e029e69 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/AppExceptionHandler.java @@ -0,0 +1,52 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.exceptions; + +import org.onap.dcaegen2.platform.mod.models.GenericResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +/** + * @author + * @date 09/08/2020 + * Exception handler for the Auth Service Application + */ +@ControllerAdvice +@Slf4j +public class AppExceptionHandler { + + @ExceptionHandler + public ResponseEntity resolveRuntimeException(UserAlreadyExistsException ex){ + log.error(ex.getMessage()); + return new ResponseEntity<>(new GenericResponse(ex.getMessage()), HttpStatus.CONFLICT); + } + + @ExceptionHandler + public ResponseEntity resolveRoleNotFoundException(RoleNotExistsException ex){ + log.error(ex.getMessage()); + return new ResponseEntity<>(new GenericResponse(ex.getMessage()), HttpStatus.BAD_REQUEST); + } +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/IllegalUserOperationException.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/IllegalUserOperationException.java new file mode 100644 index 0000000..4a5837a --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/IllegalUserOperationException.java @@ -0,0 +1,34 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.exceptions; + +/** + * @author + * @date 09/08/2020 + * Exception for Illegal Operation + */ +public class IllegalUserOperationException extends RuntimeException { + public IllegalUserOperationException(String s) { + super(s); + } +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/RoleNotExistsException.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/RoleNotExistsException.java new file mode 100644 index 0000000..dfa6efb --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/RoleNotExistsException.java @@ -0,0 +1,34 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.exceptions; + +/** + * @author + * @date 09/08/2020 + * Exception for Role not exist + */ +public class RoleNotExistsException extends RuntimeException { + public RoleNotExistsException(String message) { + super(message); + } +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/UserAlreadyExistsException.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/UserAlreadyExistsException.java new file mode 100644 index 0000000..475dc44 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/UserAlreadyExistsException.java @@ -0,0 +1,34 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.exceptions; + +/** + * @author + * @date 09/08/2020 + * Exception for User already exists + */ +public class UserAlreadyExistsException extends RuntimeException { + public UserAlreadyExistsException(String message) { + super(message); + } +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/UserNotFoundException.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/UserNotFoundException.java new file mode 100644 index 0000000..95c6a70 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/UserNotFoundException.java @@ -0,0 +1,34 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.exceptions; + +/** + * @author + * @date 09/08/2020 + * Exception for User Not Found + */ +public class UserNotFoundException extends RuntimeException { + public UserNotFoundException(String s) { + super(s); + } +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/GenericResponse.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/GenericResponse.java new file mode 100644 index 0000000..c4625a4 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/GenericResponse.java @@ -0,0 +1,40 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.models; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +/** + * @author + * @date 09/08/2020 + * Generic Response for the Auth Service Request + */ +@Getter +@Setter +@AllArgsConstructor +public class GenericResponse { + + private String message; +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/JwtResponse.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/JwtResponse.java new file mode 100644 index 0000000..8855245 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/JwtResponse.java @@ -0,0 +1,50 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.models; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author + * @date 09/08/2020 + * JWT Response for the Auth Service Request + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class JwtResponse { + + private String token; + private String type = "Bearer"; + private String id; + private String username; + private String fullName; + private List roles; + +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/LoginRequest.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/LoginRequest.java new file mode 100644 index 0000000..af0f710 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/LoginRequest.java @@ -0,0 +1,43 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.models; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * @author + * @date 09/08/2020 + * Login request + */ +@Data +public class LoginRequest { + + @NotBlank + private String username; + + @NotBlank + private String password; + +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/ModUser.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/ModUser.java new file mode 100644 index 0000000..4da5c98 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/ModUser.java @@ -0,0 +1,75 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.models; + +import lombok.Data; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.DBRef; +import org.springframework.data.mongodb.core.mapping.Document; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +/** + * @author + * @date 09/08/2020 + * Assigning Roles to User + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Document(collection = "users") +public class ModUser implements Serializable { + + @Id + public String _id; + + @NotBlank + @Size(max = 10) + private String username; + + @NotBlank + private String password; + + @NotBlank + private String fullName; + + @DBRef + private Set roles = new HashSet<>(); + + public ModUser(@NotBlank @Size(max = 10) String username, @NotBlank String password, @NotBlank String fullName) { + this.username = username; + this.password = password; + this.fullName=fullName; + } +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/Role.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/Role.java new file mode 100644 index 0000000..8cce344 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/Role.java @@ -0,0 +1,50 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.models; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +/** + * @author + * @date 09/08/2020 + * Roles + */ +@Document(collection = "roles") +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Role { + + @Id + private String id; + + private String name; + + public Role(String name) { + this.name = name; + } +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/SignupRequest.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/SignupRequest.java new file mode 100644 index 0000000..f705d76 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/SignupRequest.java @@ -0,0 +1,53 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.models; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Set; + +/** + * @author + * @date 09/08/2020 + * To validate User enter Details + */ +@Data +public class SignupRequest { + + @NotBlank(message = "username must not be blank") + @Size(min = 5, max = 10, message = "username must be between 5 and 10 characters.") + private String username; + + @NotNull(message = "username must not be null") + @Size(min = 1, message = "At least 1 role must be passed") + private Set roles; + + @NotBlank(message = "password must not be blank") + private String password; + + @NotBlank(message = "Full name must not be blank") + private String fullName; +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/UpdateUserRequest.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/UpdateUserRequest.java new file mode 100644 index 0000000..6e3abf6 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/UpdateUserRequest.java @@ -0,0 +1,47 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.models; + +import lombok.Data; + +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Set; + +/** + * @author + * @date 09/08/2020 + * To update User Details of Name and Password + */ +@Data +public class UpdateUserRequest { + + @Size(min = 1, message = "At least 1 role must be passed") + private Set roles; + + @Pattern(regexp = "^(?!\\s*$).+", message = "password must not be blank") + private String password; + + @Pattern(regexp = "^(?!\\s*$).+", message = "fullName must not be blank") + private String fullName; +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/repositories/RoleRepository.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/repositories/RoleRepository.java new file mode 100644 index 0000000..6efad17 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/repositories/RoleRepository.java @@ -0,0 +1,37 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.repositories; + +import org.onap.dcaegen2.platform.mod.models.Role; +import org.springframework.data.mongodb.repository.MongoRepository; + +import java.util.Optional; + +/** + * @author + * @date 09/08/2020 + * Interface to find user exists or not + */ +public interface RoleRepository extends MongoRepository { + Optional findByName(String name); +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/repositories/UserRepository.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/repositories/UserRepository.java new file mode 100644 index 0000000..442ebf1 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/repositories/UserRepository.java @@ -0,0 +1,40 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.repositories; + +import org.onap.dcaegen2.platform.mod.models.ModUser; +import org.springframework.data.mongodb.repository.MongoRepository; + +import java.util.Optional; + +/** + * @author + * @date 09/08/2020 + * Interface to Find/Valid/Delete user + */ +public interface UserRepository extends MongoRepository{ + Optional findByUsername(String username); + Boolean existsByUsername(String username); + void deleteByUsername(String username); +} + diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/WebSecurityConfigurer.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/WebSecurityConfigurer.java new file mode 100644 index 0000000..cfccce4 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/WebSecurityConfigurer.java @@ -0,0 +1,92 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.security; + +import org.onap.dcaegen2.platform.mod.security.jwt.AuthEntryPointJwt; +import org.onap.dcaegen2.platform.mod.security.jwt.AuthTokenFilter; +import org.onap.dcaegen2.platform.mod.security.services.UserDetailsServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + + +/** + * @author + * @date 09/08/2020 + * Allows customization to the Spring WebSecurity + */ + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { + + @Autowired + UserDetailsServiceImpl userDetailsService; + + @Autowired + private AuthEntryPointJwt unauthorizedHandler; + + @Bean + public AuthTokenFilter authenticationJwtTokenFilter(){ + return new AuthTokenFilter(); + } + + @Override + protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { + authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); + } + + @Bean + @Override + public AuthenticationManager authenticationManagerBean() throws Exception{ + return super.authenticationManagerBean(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.cors().and().csrf().disable() + .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() + .authorizeRequests().antMatchers("/api/auth/**").permitAll() + .antMatchers("/api/users/**").permitAll() + .anyRequest().authenticated(); + + http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class); + } +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/AuthEntryPointJwt.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/AuthEntryPointJwt.java new file mode 100644 index 0000000..310d487 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/AuthEntryPointJwt.java @@ -0,0 +1,51 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.security.jwt; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author + * @date 09/08/2020 + * JWT Authentication Entry Point + */ + +@Slf4j +@Component +public class AuthEntryPointJwt implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, + AuthenticationException authException) throws IOException, ServletException { + log.error("Unauthorized error: {}", authException.getMessage()); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error: Unauthorized"); + } +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/AuthTokenFilter.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/AuthTokenFilter.java new file mode 100644 index 0000000..012c333 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/AuthTokenFilter.java @@ -0,0 +1,81 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.security.jwt; + +import org.onap.dcaegen2.platform.mod.security.services.UserDetailsServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author + * @date 09/08/2020 + * Authentication Token Filter + */ +@Slf4j +public class AuthTokenFilter extends OncePerRequestFilter { + + @Autowired + private JwtUtils jwtUtils; + + @Autowired + private UserDetailsServiceImpl userDetailsService; + + @Override + protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { + try{ + String jwt = parseJwt(httpServletRequest); + if (jwt != null && jwtUtils.validateJwtToken(jwt)){ + String username = jwtUtils.getUserNameFromJwtToken(jwt); + UserDetails userDetails = userDetailsService.loadUserByUsername(username); + UsernamePasswordAuthenticationToken authenticationToken = + new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest)); + SecurityContextHolder.getContext().setAuthentication(authenticationToken); + } + }catch (Exception e){ + logger.error("Cannot set user authentication: {}", e); + } + filterChain.doFilter(httpServletRequest, httpServletResponse); + } + + private String parseJwt(HttpServletRequest httpServletRequest) { + String headerAuth = httpServletRequest.getHeader("Authorization"); + + if(StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")){ + return headerAuth.substring(7, headerAuth.length()); + } + return null; + } +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/JwtUtils.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/JwtUtils.java new file mode 100644 index 0000000..3b6d311 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/JwtUtils.java @@ -0,0 +1,90 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.security.jwt; + +import org.onap.dcaegen2.platform.mod.security.services.UserDetailsImpl; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.SignatureException; +import io.jsonwebtoken.MalformedJwtException; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.UnsupportedJwtException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Component; + +import java.util.Date; + +/** + * @author + * @date 09/08/2020 + * JWT Utils + */ +@Slf4j +@Component +public class JwtUtils { + + @Value("${mod-portal.jwt.secret}") + private String jwtSecret; + + @Value("${mod-portal.jwt.jwtExpirationMs}") + private int jwtExpirationMs; + + public String generateJwtToken(Authentication authentication) { + + UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal(); + + return Jwts.builder() + .setSubject((userPrincipal.getUsername())) + .claim("roles", userPrincipal.getAuthoritiesAsList()) + .claim("fullName", userPrincipal.getFullName()) + .setIssuedAt(new Date()) + .setExpiration(new Date((new Date()).getTime() + jwtExpirationMs)) + .signWith(SignatureAlgorithm.HS512, jwtSecret) + .compact(); + } + + public String getUserNameFromJwtToken(String token) { + return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody().getSubject(); + } + + public boolean validateJwtToken(String authToken) { + try { + Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken); + return true; + } catch (SignatureException e) { + log.error("Invalid JWT signature: {}", e.getMessage()); + } catch (MalformedJwtException e) { + log.error("Invalid JWT token: {}", e.getMessage()); + } catch (ExpiredJwtException e) { + log.error("JWT token is expired: {}", e.getMessage()); + } catch (UnsupportedJwtException e) { + log.error("JWT token is unsupported: {}", e.getMessage()); + } catch (IllegalArgumentException e) { + log.error("JWT claims string is empty: {}", e.getMessage()); + } + + return false; + } +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/services/UserDetailsImpl.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/services/UserDetailsImpl.java new file mode 100644 index 0000000..82cb577 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/services/UserDetailsImpl.java @@ -0,0 +1,127 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.security.services; + +import org.onap.dcaegen2.platform.mod.models.ModUser; +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.EqualsAndHashCode; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author + * @date 09/08/2020 + * User Details Implementation + */ +@EqualsAndHashCode +public class UserDetailsImpl implements UserDetails{ + + private static final long serialVersionUID = 1L; + + private String id; + + private String username; + + private String fullName; + + @JsonIgnore + private String password; + + private Collection authorities; + + public UserDetailsImpl(String id, String username, String fullName, String password, Collection authorities) { + this.id = id; + this.username = username; + this.fullName = fullName; + this.password = password; + this.authorities = authorities; + } + + public static UserDetails build(ModUser user) { + List authorities = user.getRoles().stream() + .map(role -> new SimpleGrantedAuthority(role.getName())) + .collect(Collectors.toList()); + + return new UserDetailsImpl( + user.get_id(), + user.getUsername(), + user.getFullName(), + user.getPassword(), + authorities + ); + } + + public String getId() { + return id; + } + + @Override + public Collection getAuthorities() { + return authorities; + } + + public List getAuthoritiesAsList(){ + return authorities.stream().map(GrantedAuthority::getAuthority) + .collect(Collectors.toList()); + } + + @Override + public String getPassword() { + return password; + } + + @Override + public String getUsername() { + return username; + } + + public String getFullName() { + return fullName; + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/services/UserDetailsServiceImpl.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/services/UserDetailsServiceImpl.java new file mode 100644 index 0000000..5c13e11 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/services/UserDetailsServiceImpl.java @@ -0,0 +1,100 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.security.services; + +import org.onap.dcaegen2.platform.mod.controllers.AuthController; +import org.onap.dcaegen2.platform.mod.exceptions.UserNotFoundException; +import org.onap.dcaegen2.platform.mod.exceptions.IllegalUserOperationException; +import org.onap.dcaegen2.platform.mod.models.ModUser; +import org.onap.dcaegen2.platform.mod.models.Role; +import org.onap.dcaegen2.platform.mod.models.UpdateUserRequest; +import org.onap.dcaegen2.platform.mod.repositories.UserRepository; +import org.onap.dcaegen2.platform.mod.security.jwt.JwtUtils; +import lombok.Setter; +import org.springframework.beans.factory.annotation.Autowired; +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 java.util.Set; + +/** + * @author + * @date 09/08/2020 + * User Details Service + */ +@Service +public class UserDetailsServiceImpl implements UserDetailsService { + + @Autowired + @Setter + UserRepository userRepository; + + @Autowired + PasswordEncoder passwordEncoder; + + @Autowired + AuthController authController; + + @Autowired + private JwtUtils jwtUtils; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + ModUser user = userRepository.findByUsername(username) + .orElseThrow(() -> new UsernameNotFoundException("User not found with username: " + username)); + + return UserDetailsImpl.build(user); + } + + public ModUser adminUpdateUser(String username, UpdateUserRequest userRequest, String token) { + return updateUserProfile(username, userRequest); + } + + public ModUser userUpdateOwnProfile(String username, UpdateUserRequest userRequest, String token) { + String usernameFromToken = jwtUtils.getUserNameFromJwtToken(token.substring(7)); + if (usernameFromToken.equals(username)) { + return updateUserProfile(username, userRequest); + } else { + throw new IllegalUserOperationException("Permission denied to update user profile of " + username); + } + } + + private ModUser updateUserProfile(String username, UpdateUserRequest userRequest) { + ModUser modUser = userRepository.findByUsername(username).orElseThrow(() -> new UserNotFoundException(String.format("User %s not found", username))); + modUser = updateUserFields(modUser, userRequest); + return userRepository.save(modUser); + } + + private ModUser updateUserFields(ModUser modUser, UpdateUserRequest userRequest) { + if (userRequest.getFullName() != null) modUser.setFullName(userRequest.getFullName()); + if (userRequest.getPassword() != null) modUser.setPassword(passwordEncoder.encode(userRequest.getPassword())); + if (userRequest.getRoles() != null) { + Set roles = authController.createRoles(userRequest.getRoles()); + modUser.setRoles(roles); + } + return modUser; + } +} diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/services/MODUserDetailService.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/services/MODUserDetailService.java new file mode 100644 index 0000000..a6a6de5 --- /dev/null +++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/services/MODUserDetailService.java @@ -0,0 +1,56 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.services; + +import org.onap.dcaegen2.platform.mod.models.ModUser; +import org.onap.dcaegen2.platform.mod.repositories.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author + * @date 09/08/2020 + * This Service provides APIs to manage User Entity + */ + +@Service +public class MODUserDetailService { + + @Autowired + private UserRepository userRepository; + + public MODUserDetailService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + public List findAll() { + return userRepository.findAll(); + } + + public void deleteUserByUsername(String username) { + userRepository.deleteByUsername(username); + } + +} diff --git a/mod2/auth-service/src/main/resources/application.properties b/mod2/auth-service/src/main/resources/application.properties new file mode 100644 index 0000000..f3f5d37 --- /dev/null +++ b/mod2/auth-service/src/main/resources/application.properties @@ -0,0 +1,32 @@ +# +# /* +# * ============LICENSE_START======================================================= +# * org.onap.dcae +# * ================================================================================ +# * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. +# * ================================================================================ +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * ============LICENSE_END========================================================= +# */ +# + +server.port=8082 + +#spring.data.mongodb.host=mongo_db +spring.data.mongodb.host=localhost +#spring.data.mongodb.host=zlecdyh2bdcc1s2dokr05.ec53e7.dyh2b.tci.att.com +spring.data.mongodb.port=27017 +spring.data.mongodb.database=dcae_mod + +mod-portal.jwt.secret=mod2020! +mod-portal.jwt.jwtExpirationMs=43200000 \ No newline at end of file diff --git a/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/AuthObjectMother.java b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/AuthObjectMother.java new file mode 100644 index 0000000..3a22af3 --- /dev/null +++ b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/AuthObjectMother.java @@ -0,0 +1,85 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.objectmothers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.onap.dcaegen2.platform.mod.models.LoginRequest; +import org.onap.dcaegen2.platform.mod.models.ModUser; +import org.onap.dcaegen2.platform.mod.models.Role; +import org.onap.dcaegen2.platform.mod.models.SignupRequest; +import org.onap.dcaegen2.platform.mod.security.services.UserDetailsImpl; +import org.onap.dcaegen2.platform.mod.util.TestUtil; +import org.springframework.security.core.authority.SimpleGrantedAuthority; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author + * @date 09/22/2020 + * Mock for AuthenticationController Test Case + */ + +public class AuthObjectMother { + public static final String LOGIN_REQUEST = "src/test/resources/http/requests/AuthLoginRequest.json"; + public static final String SIGNUP_REQUEST = "src/test/resources/http/requests/AuthSignupRequest.json"; + + public static String asJsonString(final Object object) { + try { + return new ObjectMapper().writeValueAsString(object); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static LoginRequest getLoginRequest() { + return TestUtil.deserializeJsonFileToModel(LOGIN_REQUEST, LoginRequest.class); + } + + public static SignupRequest getSignupRequest() { + return TestUtil.deserializeJsonFileToModel(SIGNUP_REQUEST, SignupRequest.class); + } + + public static UserDetailsImpl getUserDetailsImpl() { + SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("ROLE_ADMIN"); + List authorities = new ArrayList(); + authorities.add(simpleGrantedAuthority); + return new UserDetailsImpl("admin123", "admin123", "admin123", "admin123", authorities); + } + + public static ModUser getModUser() { + ModUser user = new ModUser(); + user.setUsername("test"); + user.setFullName("test"); + user.setPassword("password"); + Set roles = new HashSet<>(); + Role role = new Role(); + role.setName("test"); + role.setId("123"); + roles.add(role); + user.setRoles(roles); + return user; + } +} diff --git a/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/RoleObjectMother.java b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/RoleObjectMother.java new file mode 100644 index 0000000..68002ac --- /dev/null +++ b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/RoleObjectMother.java @@ -0,0 +1,56 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.objectmothers; + + +import org.onap.dcaegen2.platform.mod.models.ModUser; +import org.onap.dcaegen2.platform.mod.models.Role; +import org.onap.dcaegen2.platform.mod.repositories.RoleRepository; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author + * @date 09/22/2020 + * Mock for RoleController Test Case + */ +public class RoleObjectMother { + + public static List getRoles() { + List roles = new ArrayList(); + Role role1 = new Role(); + role1.setId("123"); + role1.setName("Admin123"); + + Role role2 = new Role(); + role2.setId("1234"); + role2.setName("Admin1234"); + + roles.add(role1); + roles.add(role2); + + return roles; + } + +} diff --git a/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/UserObjectMother.java b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/UserObjectMother.java new file mode 100644 index 0000000..301b81f --- /dev/null +++ b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/UserObjectMother.java @@ -0,0 +1,100 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.objectmothers; + + +import org.onap.dcaegen2.platform.mod.models.ModUser; +import org.onap.dcaegen2.platform.mod.models.Role; +import org.onap.dcaegen2.platform.mod.models.UpdateUserRequest; +import org.onap.dcaegen2.platform.mod.security.services.UserDetailsImpl; +import org.springframework.security.core.authority.SimpleGrantedAuthority; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author + * @date 09/22/2020 + * Mock for UserController Test Case + */ +public class UserObjectMother { + + public static final String userId = "admin"; + + public static List getUsers() { + List users = new ArrayList(); + ModUser modUser1 = new ModUser(); + modUser1.set_id("123"); + modUser1.setFullName("Admin123"); + modUser1.setPassword("Admin123"); + Set roles = new HashSet<>(); + Role role = new Role(); + role.setName("test"); + role.setId("123"); + roles.add(role); + modUser1.setRoles(roles); + + ModUser modUser2 = new ModUser(); + modUser2.set_id("1234"); + modUser2.setFullName("Admin1234"); + modUser2.setPassword("Admin1234"); + Set roles1 = new HashSet<>(); + Role role1 = new Role(); + role.setName("test1"); + role.setId("1234"); + roles.add(role1); + modUser2.setRoles(roles1); + + users.add(modUser1); + users.add(modUser2); + + return users; + } + + public static ModUser getModUser() { + ModUser user = new ModUser(); + user.setUsername("test"); + user.setFullName("test"); + user.setPassword("password"); + Set roles = new HashSet<>(); + Role role = new Role(); + role.setName("test"); + role.setId("123"); + roles.add(role); + user.setRoles(roles); + return user; + } + + public static UpdateUserRequest getUpdateUserRequest(){ + UpdateUserRequest user = new UpdateUserRequest(); + user.setFullName("test"); + user.setPassword("password"); + Set roles = new HashSet<>(); + roles.add("ROLE_PST"); + user.setRoles(roles); + return user; + } + +} diff --git a/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/util/TestUtil.java b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/util/TestUtil.java new file mode 100644 index 0000000..111653f --- /dev/null +++ b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/util/TestUtil.java @@ -0,0 +1,60 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.util; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +/** + * @author + * @date 09/22/2020 + * TestUtils for test cases + */ +public class TestUtil { + + private static final ObjectMapper MAPPER = new ObjectMapper(); + + private TestUtil() {} + + public static Map readJsonFileAsObjectMap(String filePath) { + try { + return MAPPER.readValue(new File(filePath), new TypeReference>() {}); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(); + } + } + + public static T deserializeJsonFileToModel(String filePath, Class modelClass) { + try { + return MAPPER.readValue(new File(filePath), modelClass); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(); + } + } +} diff --git a/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/AuthControllerTest.java b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/AuthControllerTest.java new file mode 100644 index 0000000..2aad289 --- /dev/null +++ b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/AuthControllerTest.java @@ -0,0 +1,149 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.web; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import org.junit.Assert; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.onap.dcaegen2.platform.mod.controllers.AuthController; +import org.onap.dcaegen2.platform.mod.models.*; +import org.onap.dcaegen2.platform.mod.repositories.RoleRepository; +import org.onap.dcaegen2.platform.mod.repositories.UserRepository; +import org.onap.dcaegen2.platform.mod.security.jwt.AuthEntryPointJwt; +import org.onap.dcaegen2.platform.mod.security.jwt.JwtUtils; +import org.onap.dcaegen2.platform.mod.security.services.UserDetailsServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.*; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.client.RestTemplate; +import org.testng.annotations.BeforeTest; + +import java.io.IOException; +import java.util.Optional; + +import static org.hamcrest.core.IsNull.notNullValue; +import static org.mockito.Mockito.*; +import static org.onap.dcaegen2.platform.mod.objectmothers.AuthObjectMother.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * @author + * @date 09/22/2020 + * Mock Test cases for AuthenticationController + */ +@WebMvcTest(AuthController.class) +public class AuthControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + JwtUtils jwtUtils; + + @MockBean + AuthenticationManager authenticationManager; + + @MockBean + UserRepository userRepository; + + @MockBean + RoleRepository roleRepository; + + @MockBean + PasswordEncoder passwordEncoder; + + @MockBean + UserDetailsServiceImpl userDetailsService; + + @MockBean + AuthEntryPointJwt authEntryPointJwt; + + @Mock + Authentication authentication; + + @BeforeEach + void setUp() { + } + + + @Test + void test_signin_returnsSuccessResponse() throws Exception { + + LoginRequest loginRequest = getLoginRequest(); + + when(authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()))).thenReturn(authentication); + when(authentication.getPrincipal()).thenReturn(getUserDetailsImpl()); + when(jwtUtils.generateJwtToken(any())).thenReturn("Demo"); + + mockMvc.perform(post("/api/auth/signin") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(loginRequest)).accept(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.token", notNullValue())) + .andExpect(status().isOk()); + + verify(authenticationManager, times(1)).authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword())); + verify(jwtUtils, times(1)).generateJwtToken(any()); + } + + + @WithMockUser(roles="ADMIN") + @Test + void test_signup_returnsSuccessResponse() throws Exception { + + SignupRequest signUpRequest = getSignupRequest(); + + when(userRepository.existsByUsername(signUpRequest.getUsername())).thenReturn(false); + when(passwordEncoder.encode(signUpRequest.getPassword())).thenReturn("password"); + when(roleRepository.findByName(anyString())).thenReturn(Optional.of(new Role())); + when(userRepository.save(any())).thenReturn(getModUser()); + + mockMvc.perform(post("/api/auth/signup") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(signUpRequest)).accept(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.message", notNullValue())) + .andExpect(status().isOk()); + + verify(userRepository, times(1)).existsByUsername(signUpRequest.getUsername()); + verify(passwordEncoder, times(1)).encode(signUpRequest.getPassword()); + verify(roleRepository, times(1)).findByName(anyString()); + verify(userRepository, times(1)).save(any()); + } + + +} diff --git a/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/RoleControllerTest.java b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/RoleControllerTest.java new file mode 100644 index 0000000..48b5d4b --- /dev/null +++ b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/RoleControllerTest.java @@ -0,0 +1,109 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.web; + +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.onap.dcaegen2.platform.mod.controllers.RoleController; +import org.onap.dcaegen2.platform.mod.models.ModUser; +import org.onap.dcaegen2.platform.mod.models.Role; +import org.onap.dcaegen2.platform.mod.repositories.RoleRepository; +import org.onap.dcaegen2.platform.mod.security.jwt.AuthEntryPointJwt; +import org.onap.dcaegen2.platform.mod.security.jwt.JwtUtils; +import org.onap.dcaegen2.platform.mod.security.services.UserDetailsServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.security.core.Authentication; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseStatus; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.hamcrest.core.IsNull.notNullValue; +import static org.onap.dcaegen2.platform.mod.objectmothers.AuthObjectMother.asJsonString; +import static org.onap.dcaegen2.platform.mod.objectmothers.RoleObjectMother.getRoles; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * @author + * @date 09/22/2020 + * Mock Test cases for RoleController + */ +@WebMvcTest(RoleController.class) +public class RoleControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + RoleRepository roleRepository; + + @MockBean + UserDetailsServiceImpl userDetailsService; + + @MockBean + AuthEntryPointJwt authEntryPointJwt; + + @MockBean + JwtUtils jwtUtils; + + @Mock + Authentication authentication; + + @BeforeEach + void setUp() { + } + + + @Test + void test_getRoles() throws Exception { + + Mockito.when(roleRepository.findAll()).thenReturn(getRoles()); + + MvcResult result = mockMvc.perform(get("/api/roles") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()).andReturn(); + + Assert.assertNotNull(result.getResponse().getContentAsString()); + + } + +} diff --git a/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/UserControllerTest.java b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/UserControllerTest.java new file mode 100644 index 0000000..1374e0e --- /dev/null +++ b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/UserControllerTest.java @@ -0,0 +1,168 @@ +/* + * + * * ============LICENSE_START======================================================= + * * org.onap.dcae + * * ================================================================================ + * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved. + * * ================================================================================ + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * ============LICENSE_END========================================================= + * + */ + +package org.onap.dcaegen2.platform.mod.web; + +import org.apache.tools.ant.taskdefs.optional.extension.Specification; +import org.junit.Assert; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.runner.Request; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.onap.dcaegen2.platform.mod.controllers.RoleController; +import org.onap.dcaegen2.platform.mod.controllers.UserController; +import org.onap.dcaegen2.platform.mod.models.LoginRequest; +import org.onap.dcaegen2.platform.mod.models.ModUser; +import org.onap.dcaegen2.platform.mod.models.UpdateUserRequest; +import org.onap.dcaegen2.platform.mod.repositories.RoleRepository; +import org.onap.dcaegen2.platform.mod.repositories.UserRepository; +import org.onap.dcaegen2.platform.mod.security.jwt.AuthEntryPointJwt; +import org.onap.dcaegen2.platform.mod.security.jwt.JwtUtils; +import org.onap.dcaegen2.platform.mod.security.services.UserDetailsServiceImpl; +import org.onap.dcaegen2.platform.mod.services.MODUserDetailService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.security.core.Authentication; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.client.RequestMatcher; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.ResultMatcher; + +import java.util.Optional; + +import static org.hamcrest.Matchers.notNullValue; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; +import static org.onap.dcaegen2.platform.mod.objectmothers.AuthObjectMother.asJsonString; +import static org.onap.dcaegen2.platform.mod.objectmothers.AuthObjectMother.getModUser; +import static org.onap.dcaegen2.platform.mod.objectmothers.RoleObjectMother.getRoles; +import static org.onap.dcaegen2.platform.mod.objectmothers.UserObjectMother.*; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.content; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * @author + * @date 09/22/2020 + * Mock Test cases for UserController + */ +@WebMvcTest(UserController.class) +public class UserControllerTest { + + + @Autowired + private MockMvc mockMvc; + + @MockBean + UserDetailsServiceImpl userDetailsService; + + @MockBean + UserRepository userRepository; + + @MockBean + MODUserDetailService modUserDetailService; + + @MockBean + RoleRepository roleRepository; + + @MockBean + AuthEntryPointJwt authEntryPointJwt; + + @MockBean + JwtUtils jwtUtils; + + @Mock + Authentication authentication; + + + @BeforeEach + void setUp() { + } + + @WithMockUser(roles="ADMIN") + @Test + void test_getUsername() throws Exception { + + when(userRepository.findByUsername(any())).thenReturn(Optional.of(new ModUser())); + + MvcResult result = mockMvc.perform(get("/api/users/" + userId) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()).andReturn(); + + Assert.assertNotNull(result.getResponse().getContentAsString()); + verify(userRepository, times(1)).findByUsername(any()); + } + + @Test + void test_getAllUsers() throws Exception { + + when(modUserDetailService.findAll()).thenReturn(getUsers()); + + MvcResult result = mockMvc.perform(get("/api/users/getAll") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()).andReturn(); + + Assert.assertNotNull(result.getResponse().getContentAsString()); + verify(modUserDetailService, times(1)).findAll(); + } + + + @WithMockUser(roles="ADMIN") + @Test + void test_deleteUser() throws Exception { + + doNothing().when(modUserDetailService).deleteUserByUsername(any(String.class)); + + MvcResult result = mockMvc.perform(delete("/api/users/" + userId) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()).andReturn(); + + Assert.assertNotNull(result.getResponse().getContentAsString()); + verify(modUserDetailService, times(1)).deleteUserByUsername(any(String.class)); + } + + + @WithMockUser(username="ADMIN") + @Test + void test_userUpdateOwnProfile_returnsSuccessResponse() throws Exception { + //arrange + UpdateUserRequest updateUserRequest = getUpdateUserRequest(); + + when(userDetailsService.adminUpdateUser(userId,updateUserRequest,"token")).thenReturn(getModUser()); + + mockMvc.perform(patch("/api/users/admin/" + userId) + //.header("Authorization", "token") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(updateUserRequest)).accept(MediaType.APPLICATION_JSON)) + //.andExpect(jsonPath("$.message", notNullValue())) + .andExpect(status().isOk()).andReturn(); + + verify(userDetailsService, times(1)).adminUpdateUser(anyString(),updateUserRequest,anyString()); + } + + +} \ No newline at end of file diff --git a/mod2/auth-service/src/test/resources/application.properties b/mod2/auth-service/src/test/resources/application.properties new file mode 100644 index 0000000..d6a913c --- /dev/null +++ b/mod2/auth-service/src/test/resources/application.properties @@ -0,0 +1 @@ +#spring.data.mongodb.port=0 \ No newline at end of file diff --git a/mod2/auth-service/src/test/resources/http/requests/AuthLoginRequest.json b/mod2/auth-service/src/test/resources/http/requests/AuthLoginRequest.json new file mode 100644 index 0000000..fbdc4a9 --- /dev/null +++ b/mod2/auth-service/src/test/resources/http/requests/AuthLoginRequest.json @@ -0,0 +1,4 @@ +{ + "username": "admin", + "password": "admin@mod" +} diff --git a/mod2/auth-service/src/test/resources/http/requests/AuthSignupRequest.json b/mod2/auth-service/src/test/resources/http/requests/AuthSignupRequest.json new file mode 100644 index 0000000..25be086 --- /dev/null +++ b/mod2/auth-service/src/test/resources/http/requests/AuthSignupRequest.json @@ -0,0 +1,6 @@ +{ + "username": "admin1", + "fullName": "Administrator", + "password": "admin@mod", + "roles": ["ROLE_PST"] +} \ No newline at end of file diff --git a/mod2/auth-service/src/test/resources/specification/componentSpec_hello_world-with-dmaap.json b/mod2/auth-service/src/test/resources/specification/componentSpec_hello_world-with-dmaap.json new file mode 100644 index 0000000..0ad6b6e --- /dev/null +++ b/mod2/auth-service/src/test/resources/specification/componentSpec_hello_world-with-dmaap.json @@ -0,0 +1,149 @@ +{ + "self": { + "component_type": "docker", + "description": "Hello World mS for subscribing the data from local DMaaP, DR or MR, processing them and publishing them as PM files to local DMaaP DR", + "name": "dcae-collectors-vcc-helloworld-pm", + "version": "1.0.1" + }, + + "services": { + "calls": [], + "provides": [] + }, + + "streams": { + "publishes": [{ + "config_key": "DCAE-HELLO-WORLD-PUB-DR", + "format": "dataformat_Hello_World_PM", + "type": "data_router", + "version": "1.0.0" + }, + { + "config_key": "DCAE-HELLO-WORLD-PUB-MR", + "format": "dataformat_Hello_World_PM", + "type": "message_router", + "version": "1.0.0" + } + ], + + "subscribes": [{ + "config_key": "DCAE-HELLO-WORLD-SUB-MR", + "format": "dataformat_Hello_World_PM", + "route": "/DCAE_HELLO_WORLD_SUB_MR", + "type": "message_router", + "version": "1.0.0" + }, + { + "config_key": "DCAE-HELLO-WORLD-SUB-DR", + "format": "dataformat_Hello_World_PM", + "route": "/DCAE-HELLO-WORLD-SUB-DR", + "type": "data_router", + "version": "1.0.0" + } + ] + }, + + "parameters": + [ + { + "name": "vcc_hello_name", + "value": "120", + "type": "integer", + "description": "the name entered for specific person", + "sourced_at_deployment": false, + "designer_editable": false, + "policy_editable": false + }, + + { + "name": "useDtiConfig", + "value": false, + "type" : "boolean", + "description": "component depends on configuration from dti.", + "sourced_at_deployment": false, + "designer_editable": true, + "policy_editable": false, + "required" : true + }, + + { + "name": "isSelfServeComponent", + "value": false, + "type": "boolean", + "description": "Is this used as self serve component.", + "sourced_at_deployment": false, + "designer_editable": true, + "policy_editable": false, + "required" : true + } + ], + + "auxilary": { + "healthcheck": { + "interval": "60s", + "initialDelaySeconds": "120s", + "timeout": "20s", + "script": "/opt/app/vcc/bin/common/HealthCheck_HelloWorld.sh", + "type": "docker" + }, + "livehealthcheck": { + "interval": "60s", + "initialDelaySeconds": "120s", + "timeout": "20s", + "script": "/opt/app/vcc/bin/common/HealthCheck_HelloWorld.sh", + "type": "docker" + }, + "reconfigs":{ + "app_reconfig" : "abc" + }, + + "volumes": [ + { + "container": { + "bind": "/opt/app/dcae-certificate" + }, + "host": { + "path": "/opt/app/dcae-certificate" + } + }, + { + "container": { + "bind": "/opt/logs/DCAE/dmd/AGENT" + }, + "host": { + "path": "/opt/logs/DCAE/helloworldpm/dmd/AGENT" + } + }, + { + "container": { + "bind": "/opt/logs/DCAE/dmd/WATCHER" + }, + "host": { + "path": "/opt/logs/DCAE/helloworldpm/dmd/WATCHER" + } + }, + { + "container": { + "bind": "/opt/app/vcc/logs/DCAE" + }, + "host": { + "path": "/opt/logs/DCAE/helloworldpm/vcc-logs" + } + }, + { + "container": { + "bind": "/opt/app/vcc/archive/data" + }, + "host": { + "path": "/opt/data/DCAE/helloworldpm/vcc-archive" + } + } + + ] + + }, + "artifacts": [{ + "type": "docker image", + "uri": "dockercentral.it.att.com:5100/com.att.sample/dcae-controller-vcc-helloworld-pm:18.02-001" + }] +} \ No newline at end of file diff --git a/mod2/auth-service/src/test/resources/specification/policy_json_sample_3.json b/mod2/auth-service/src/test/resources/specification/policy_json_sample_3.json new file mode 100644 index 0000000..4a8c76f --- /dev/null +++ b/mod2/auth-service/src/test/resources/specification/policy_json_sample_3.json @@ -0,0 +1,28 @@ +{ + "policies": [ + { + "configAttributes": "", + "configName": "", + "onapName": "DCAE", + "policyName": "DCAE.Config_", + "unique": false + }, + { + "onapName": "DCAE", + "policyName": "DCAE.Config_", + "unique": true + }, + { + "configAttributes": "", + "configName": "", + "onapName": "DCAE", + "policyName": "DCAE.Config_*", + "unique": false + } + ], + "policy": [ + { + "policy_id" : "id_0" + } + ] +} \ No newline at end of file -- cgit 1.2.3-korg