Skip to content

Commit

Permalink
Endpoint for Profile to fetch roles for user
Browse files Browse the repository at this point in the history
  • Loading branch information
oharsta committed May 28, 2024
1 parent 8ba4c83 commit 46719c8
Show file tree
Hide file tree
Showing 18 changed files with 237 additions and 27 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ Graph

Login with Mujina IdP and user `admin` to become super-user in the local environment

<http://localhost:8080/ui/swagger-ui/index.html>
<http://localhost:8888/ui/swagger-ui/index.html>

<http://localhost:8081/>

Expand Down
2 changes: 1 addition & 1 deletion client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>org.openconext</groupId>
<artifactId>access</artifactId>
<version>0.0.14</version>
<version>0.0.15-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>access-client</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.openconext</groupId>
<artifactId>access</artifactId>
<version>0.0.14</version>
<version>0.0.15-SNAPSHOT</version>
<packaging>pom</packaging>
<name>access</name>
<description>SURFconext Invite</description>
Expand Down
2 changes: 1 addition & 1 deletion provisioning-mock/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>org.openconext</groupId>
<artifactId>access</artifactId>
<version>0.0.14</version>
<version>0.0.15-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>provisioning-mock</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>org.openconext</groupId>
<artifactId>access</artifactId>
<version>0.0.14</version>
<version>0.0.15-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>access-server</artifactId>
Expand Down
8 changes: 2 additions & 6 deletions server/src/main/java/access/SwaggerOpenIdConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ public class SwaggerOpenIdConfig {

public static final String OPEN_ID_SCHEME_NAME = "openId";
public static final String API_TOKENS_SCHEME_NAME = "apiTokens";
public static final String VOOT_SCHEME_NAME = "voot";
public static final String LIFE_CYCLE_SCHEME_NAME = "lifeCycle";
public static final String ATTRIBUTE_AGGREGATION_SCHEME_NAME = "attributeAggregation";
public static final String BASIC_AUTHENTICATION_SCHEME_NAME = "basic_auth";

@Bean
OpenAPI customOpenApi(@Value("${spring.security.oauth2.client.provider.oidcng.authorization-uri}") String authorizationUrl,
Expand All @@ -48,9 +46,7 @@ OpenAPI customOpenApi(@Value("${spring.security.oauth2.client.provider.oidcng.au
Components components = new Components()
.addSecuritySchemes(OPEN_ID_SCHEME_NAME, openIdSecuritySchema)
.addSecuritySchemes(API_TOKENS_SCHEME_NAME, apiTokensSecurityScheme)
.addSecuritySchemes(VOOT_SCHEME_NAME, basicAuthentication)
.addSecuritySchemes(LIFE_CYCLE_SCHEME_NAME, basicAuthentication)
.addSecuritySchemes(ATTRIBUTE_AGGREGATION_SCHEME_NAME, basicAuthentication);
.addSecuritySchemes(BASIC_AUTHENTICATION_SCHEME_NAME, basicAuthentication);

OpenAPI openAPI = new OpenAPI()
.info(new Info()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@
import java.util.Map;
import java.util.Optional;

import static access.SwaggerOpenIdConfig.ATTRIBUTE_AGGREGATION_SCHEME_NAME;
import static access.SwaggerOpenIdConfig.BASIC_AUTHENTICATION_SCHEME_NAME;

@RestController
@RequestMapping(value = {"/api/aa", "/api/external/v1/aa"}, produces = MediaType.APPLICATION_JSON_VALUE)
@SecurityRequirement(name = ATTRIBUTE_AGGREGATION_SCHEME_NAME)
@SecurityRequirement(name = BASIC_AUTHENTICATION_SCHEME_NAME)
public class AttributeAggregatorController {

private static final Log LOG = LogFactory.getLog(AttributeAggregatorController.class);
Expand Down
14 changes: 9 additions & 5 deletions server/src/main/java/access/api/DefaultErrorController.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -23,8 +24,7 @@
import java.net.URISyntaxException;
import java.util.Map;

import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.*;

@RestController
@Hidden
Expand Down Expand Up @@ -61,9 +61,13 @@ public ResponseEntity error(HttpServletRequest request) {
boolean logStackTrace = !(error instanceof UserRestrictionException || error instanceof access.exception.RemoteException);
LOG.error(String.format("Error occurred; %s", error), logStackTrace ? error : null);
}
//https://github.com/spring-projects/spring-boot/issues/3057
ResponseStatus annotation = AnnotationUtils.getAnnotation(error.getClass(), ResponseStatus.class);
statusCode = annotation != null ? annotation.value() : BAD_REQUEST;
if (error instanceof AccessDeniedException) {
statusCode = FORBIDDEN;
} else {
//https://github.com/spring-projects/spring-boot/issues/3057
ResponseStatus annotation = AnnotationUtils.getAnnotation(error.getClass(), ResponseStatus.class);
statusCode = annotation != null ? annotation.value() : BAD_REQUEST;
}
}
result.remove("message");
result.put("status", statusCode.value());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@
import access.repository.*;

import java.util.*;
import java.util.stream.Collectors;

import static access.SwaggerOpenIdConfig.LIFE_CYCLE_SCHEME_NAME;
import static access.SwaggerOpenIdConfig.BASIC_AUTHENTICATION_SCHEME_NAME;

@RestController
@RequestMapping(value = {"/api/deprovision", "/api/external/v1/deprovision"}, produces = MediaType.APPLICATION_JSON_VALUE)
@SecurityRequirement(name = LIFE_CYCLE_SCHEME_NAME)
@SecurityRequirement(name = BASIC_AUTHENTICATION_SCHEME_NAME)
public class UserLifeCycleController {

private static final Logger LOG = LoggerFactory.getLogger(UserLifeCycleController.class);
Expand Down
20 changes: 20 additions & 0 deletions server/src/main/java/access/profile/ApplicationInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package access.profile;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class ApplicationInfo {

private String landingPage;
private String nameEn;
private String nameNl;
private String organisationEn;
private String organisationNl;
private String logo;
}
79 changes: 79 additions & 0 deletions server/src/main/java/access/profile/ProfileController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package access.profile;

import access.manage.Manage;
import access.model.Authority;
import access.model.Role;
import access.model.User;
import access.model.UserRole;
import access.repository.UserRepository;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import static access.SwaggerOpenIdConfig.BASIC_AUTHENTICATION_SCHEME_NAME;

@RestController
@RequestMapping(value = {"/api/profile", "/api/external/v1/profile"}, produces = MediaType.APPLICATION_JSON_VALUE)
@SecurityRequirement(name = BASIC_AUTHENTICATION_SCHEME_NAME)
public class ProfileController {

private static final Log LOG = LogFactory.getLog(ProfileController.class);

private final UserRepository userRepository;
private final Manage manage;

public ProfileController(UserRepository userRepository,
Manage manage) {
this.userRepository = userRepository;
this.manage = manage;
}

@GetMapping(value = "")
@PreAuthorize("hasRole('PROFILE')")
public ResponseEntity<List<UserRoleProfile>> roles(@RequestParam("collabPersonId") String collabPersonId) {
LOG.debug("Fetch profile roles for:" + collabPersonId);

Optional<User> optionalUser = userRepository.findBySubIgnoreCase(collabPersonId);
Set<UserRole> userRoles = optionalUser.map(User::getUserRoles).orElse(Collections.emptySet());
List<Role> roles = userRoles.stream()
.filter(userRole -> userRole.getAuthority().equals(Authority.GUEST))
.map(UserRole::getRole).toList();
return ResponseEntity.ok(
manage.addManageMetaData(roles).stream().
map(this::userRoleProfile)
.toList()
);
}

private UserRoleProfile userRoleProfile(Role role) {
return new UserRoleProfile(
role.getName(),
role.getDescription(),
applicationInfoList(role));
}

private List<ApplicationInfo> applicationInfoList(Role role) {
return role.getApplicationMaps().stream().map(applicationMap -> new ApplicationInfo(
(String) applicationMap.get("landingPage"),
(String) applicationMap.get("name:en"),
(String) applicationMap.get("name:nl"),
(String) applicationMap.get("OrganizationName:en"),
(String) applicationMap.get("OrganizationName:nl"),
(String) applicationMap.get("logo")
)).toList();

}

}
21 changes: 21 additions & 0 deletions server/src/main/java/access/profile/UserRoleProfile.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package access.profile;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.List;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserRoleProfile {

private String name;
private String description;
private List<ApplicationInfo> applications;


}
16 changes: 15 additions & 1 deletion server/src/main/java/access/security/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public class SecurityConfig {
private final String lifeCyclePassword;
private final String teamsUser;
private final String teamsPassword;
private final String profileUser;
private final String profilePassword;

@Autowired
public SecurityConfig(ClientRegistrationRepository clientRegistrationRepository,
Expand All @@ -80,6 +82,8 @@ public SecurityConfig(ClientRegistrationRepository clientRegistrationRepository,
@Value("${lifecycle.password}") String lifeCyclePassword,
@Value("${teams.user}") String teamsUser,
@Value("${teams.password}") String teamsPassword,
@Value("${profile.user}") String profileUser,
@Value("${profile.password}") String profilePassword,
@Value("${attribute-aggregation.user}") String attributeAggregationUser,
@Value("${attribute-aggregation.password}") String attributeAggregationPassword) {
this.clientRegistrationRepository = clientRegistrationRepository;
Expand All @@ -95,6 +99,8 @@ public SecurityConfig(ClientRegistrationRepository clientRegistrationRepository,
this.lifeCyclePassword = lifeCyclePassword;
this.teamsUser = teamsUser;
this.teamsPassword = teamsPassword;
this.profileUser = profileUser;
this.profilePassword = profilePassword;
this.attributeAggregationUser = attributeAggregationUser;
this.attributeAggregationPassword = attributeAggregationPassword;
}
Expand Down Expand Up @@ -205,6 +211,8 @@ SecurityFilterChain basicAuthenticationSecurityFilterChain(HttpSecurity http) th
"/api/external/v1/voot/**",
"/api/teams/**",
"/api/external/v1/teams/**",
"/api/profile/**",
"/api/external/v1/profile/**",
"/api/aa/**",
"/api/external/v1/aa/**",
"/api/deprovision/**",
Expand Down Expand Up @@ -268,11 +276,17 @@ public InMemoryUserDetailsManager userDetailsService() {
.password("{noop}" + lifeCyclePassword)
.roles("LIFECYCLE")
.build();
UserDetails profileUserDetails = User
.withUsername(profileUser)
.password("{noop}" + profilePassword)
.roles("PROFILE")
.build();
return new InMemoryUserDetailsManager(
vootUserDetails,
attributeAggregationUserDetails,
lifeCyleUserDetails,
teamsUserDetails);
teamsUserDetails,
profileUserDetails);
}

@Bean
Expand Down
4 changes: 2 additions & 2 deletions server/src/main/java/access/teams/TeamsController.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@
import java.util.*;
import java.util.stream.Collectors;

import static access.SwaggerOpenIdConfig.ATTRIBUTE_AGGREGATION_SCHEME_NAME;
import static access.SwaggerOpenIdConfig.BASIC_AUTHENTICATION_SCHEME_NAME;

@RestController
@RequestMapping(value = {"/api/teams", "/api/external/v1/teams"}, produces = MediaType.APPLICATION_JSON_VALUE)
@SecurityRequirement(name = ATTRIBUTE_AGGREGATION_SCHEME_NAME)
@SecurityRequirement(name = BASIC_AUTHENTICATION_SCHEME_NAME)
public class TeamsController {

private static final int DEFAULT_EXPIRY_DAYS = 5 * 365;
Expand Down
4 changes: 2 additions & 2 deletions server/src/main/java/access/voot/VootController.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@
import java.util.*;
import java.util.stream.Collectors;

import static access.SwaggerOpenIdConfig.VOOT_SCHEME_NAME;
import static access.SwaggerOpenIdConfig.BASIC_AUTHENTICATION_SCHEME_NAME;

@RestController
@RequestMapping(value = {"/api/voot", "/api/external/v1/voot"}, produces = MediaType.APPLICATION_JSON_VALUE)
@SecurityRequirement(name = VOOT_SCHEME_NAME)
@SecurityRequirement(name = BASIC_AUTHENTICATION_SCHEME_NAME)
public class VootController {

private static final Log LOG = LogFactory.getLog(VootController.class);
Expand Down
4 changes: 4 additions & 0 deletions server/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ lifecycle:
user: lifecycle
password: secret

profile:
user: profile
password: secret

email:
from: "[email protected]"
contactEmail: "[email protected]"
Expand Down
Loading

0 comments on commit 46719c8

Please sign in to comment.