Skip to content

Commit

Permalink
SHIBUI-2393
Browse files Browse the repository at this point in the history
Adding logic to send dynamic registration to shibboleth (enable)
  • Loading branch information
chasegawa committed Nov 16, 2022
1 parent 38ce6f8 commit 0d3cad2
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import edu.internet2.tier.shibboleth.admin.ui.service.JPAFilterTargetServiceImpl;
import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverService;
import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolversPositionOrderContainerService;
import edu.internet2.tier.shibboleth.admin.ui.service.ShibRestTemplateDelegate;
import edu.internet2.tier.shibboleth.admin.util.AttributeUtility;
import edu.internet2.tier.shibboleth.admin.util.EntityDescriptorConversionUtils;
import edu.internet2.tier.shibboleth.admin.util.LuceneUtility;
Expand All @@ -43,12 +44,14 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.io.Resource;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
Expand All @@ -57,6 +60,7 @@
import org.springframework.web.util.UrlPathHelper;

import javax.servlet.http.HttpServletRequest;
import java.net.URL;

@Configuration
@Import(SearchConfiguration.class)
Expand Down Expand Up @@ -243,7 +247,10 @@ public IShibUiPermissionEvaluator shibUiPermissionEvaluator(EntityDescriptorRepo
}

@Bean
public DynamicRegistrationService dynamicRegistrationService(DynamicRegistrationInfoRepository driRepo, OwnershipRepository ownershipRepo, IShibUiPermissionEvaluator permissionEvaluator, UserService userService, IGroupService groupService) {
return new JPADynamicRegistrationServiceImpl(groupService, driRepo, ownershipRepo, permissionEvaluator, userService);
public DynamicRegistrationService dynamicRegistrationService(DynamicRegistrationInfoRepository driRepo, OwnershipRepository ownershipRepo, IShibUiPermissionEvaluator permissionEvaluator, UserService userService, IGroupService groupService, ShibUIConfiguration config, RestTemplateBuilder restTemplateBuilder) {
URL idpUrl = config.getShibIdpServer();
RestTemplate template = restTemplateBuilder.build();
ShibRestTemplateDelegate delegate = new ShibRestTemplateDelegate(idpUrl, template);
return new JPADynamicRegistrationServiceImpl(groupService, driRepo, ownershipRepo, delegate, permissionEvaluator, userService);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;

import java.net.URL;
import java.util.List;
import java.util.Set;

Expand Down Expand Up @@ -39,4 +40,9 @@ public class ShibUIConfiguration {
* A list of roles to bootstrap into the system.
*/
private Set<String> roles;

/**
* The URL of the shib idp server ala - https://idp.someschool.edu/idp
*/
private URL shibIdpServer;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.tags.Tags;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PatchMapping;
Expand Down Expand Up @@ -45,8 +46,13 @@ public class ActivateController {
@Transactional
public ResponseEntity<?> enableDynamicRegistration(@PathVariable String resourceId, @PathVariable String mode) throws PersistentEntityNotFound, ForbiddenException, UnsupportedShibUiOperationException {
if ("enable".equalsIgnoreCase(mode)) {
DynamicRegistrationRepresentation drr = dynamicRegistrationService.enableDynamicRegistration(resourceId);
return ResponseEntity.ok(drr);
HttpStatus status = dynamicRegistrationService.enableDynamicRegistration(resourceId);
switch (status) {
case OK:
case ACCEPTED: return ResponseEntity.ok("Service enabled");
case NOT_FOUND: throw new UnsupportedShibUiOperationException("Request returned NOT FOUND, please contact a system admin to check configuration");
case FORBIDDEN: throw new ForbiddenException("Request was denied with FORBIDDEN, please contact a system admin to check configuration");
}
}
throw new UnsupportedShibUiOperationException("Disable is not a valid operation for Dynamic Registrations at this time");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException;
import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException;
import edu.internet2.tier.shibboleth.admin.ui.exception.PersistentEntityNotFound;
import edu.internet2.tier.shibboleth.admin.ui.exception.UnsupportedShibUiOperationException;
import org.springframework.http.HttpStatus;

import java.util.List;

Expand All @@ -15,7 +17,8 @@ DynamicRegistrationRepresentation approveDynamicRegistration(String resourceId,

void delete(String resourceId) throws ForbiddenException, PersistentEntityNotFound;

DynamicRegistrationRepresentation enableDynamicRegistration(String resourceId) throws PersistentEntityNotFound, ForbiddenException;
HttpStatus enableDynamicRegistration(String resourceId)
throws PersistentEntityNotFound, ForbiddenException, UnsupportedShibUiOperationException;

List<DynamicRegistrationRepresentation> getAllDynamicRegistrationsBasedOnUserAccess() throws ForbiddenException;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException;
import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException;
import edu.internet2.tier.shibboleth.admin.ui.exception.PersistentEntityNotFound;
import edu.internet2.tier.shibboleth.admin.ui.exception.UnsupportedShibUiOperationException;
import edu.internet2.tier.shibboleth.admin.ui.security.model.Approvers;
import edu.internet2.tier.shibboleth.admin.ui.security.model.Group;
import edu.internet2.tier.shibboleth.admin.ui.security.model.Owner;
Expand All @@ -22,6 +23,7 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
Expand All @@ -34,19 +36,21 @@
@NoArgsConstructor
public class JPADynamicRegistrationServiceImpl implements DynamicRegistrationService {
@Autowired
IGroupService groupService;
private IGroupService groupService;

@Autowired
DynamicRegistrationInfoRepository repository;
private DynamicRegistrationInfoRepository repository;

@Autowired
OwnershipRepository ownershipRepository;
private OwnershipRepository ownershipRepository;

private ShibRestTemplateDelegate shibRestTemplateDelegate;

@Autowired
private IShibUiPermissionEvaluator shibUiAuthorizationDelegate;

@Autowired
UserService userService;
private UserService userService;

@Override
public DynamicRegistrationRepresentation approveDynamicRegistration(String resourceId, boolean status) throws PersistentEntityNotFound, ForbiddenException {
Expand Down Expand Up @@ -125,16 +129,15 @@ public void delete(String resourceId) throws ForbiddenException, PersistentEntit
}

@Override
public DynamicRegistrationRepresentation enableDynamicRegistration(String resourceId) throws PersistentEntityNotFound, ForbiddenException {
public HttpStatus enableDynamicRegistration(String resourceId) throws PersistentEntityNotFound, ForbiddenException, UnsupportedShibUiOperationException {
DynamicRegistrationInfo existingDri = repository.findByResourceId(resourceId);
if (existingDri == null) {
throw new PersistentEntityNotFound(String.format("The dynamic registration with id [%s] was not found for update.", existingDri.getResourceId()));
}
if (!shibUiAuthorizationDelegate.hasPermission(userService.getCurrentUserAuthentication(), existingDri, PermissionType.enable)) {
throw new ForbiddenException("You do not have the permissions necessary to enable this service");
}
// TODO do something...
return new DynamicRegistrationRepresentation(existingDri);
return shibRestTemplateDelegate.sendRequest(existingDri);
}

private boolean entityExists(String id) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package edu.internet2.tier.shibboleth.admin.ui.service;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.internet2.tier.shibboleth.admin.ui.domain.oidc.DynamicRegistrationInfo;
import edu.internet2.tier.shibboleth.admin.ui.exception.UnsupportedShibUiOperationException;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

/**
* Requires that the shib server url be non-null
*/
public class ShibRestTemplateDelegate {
private URL shibUrl;
private RestTemplate restTemplate;

public ShibRestTemplateDelegate(URL url, RestTemplate template) {
this.restTemplate = template;
if (url != null) {
try {
shibUrl = new URL(url.toExternalForm() + "/profile/oidc/register");
}
catch (MalformedURLException e) {
shibUrl = null;
}
}
}

public HttpStatus sendRequest(DynamicRegistrationInfo dri) throws UnsupportedShibUiOperationException {
if (shibUrl == null) {
throw new UnsupportedShibUiOperationException("Dynamic Registration endpoint not configured properly, please contact your system admin.");
}
try {
ResponseEntity response = restTemplate.postForEntity(shibUrl.toURI(), convertDynamicReg(dri), Map.class);
return response.getStatusCode();
}
catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}

private Object convertDynamicReg(DynamicRegistrationInfo dri) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // skip any null values

Map<String, String> valuesMap = new HashMap<>();
valuesMap.put("redirect_uris", dri.getRedirectUris());
valuesMap.put("response_types", dri.getResponseTypes());
valuesMap.put("grant_types", dri.getGrantType().name());
valuesMap.put("application_type", dri.getApplicationType());
valuesMap.put("contacts", dri.getContacts());
valuesMap.put("subject_type", dri.getSubjectType());
valuesMap.put("jwks", dri.getJwks());
valuesMap.put("token_endpoint_auth_method", dri.getTokenEndpointAuthMethod());
valuesMap.put("logo_uri", dri.getLogoUri());
valuesMap.put("policy_uri", dri.getPolicyUri());
valuesMap.put("tos_uri", dri.getTosUri());
valuesMap.put("scope", dri.getScope());

String json;
try {
json = mapper.writeValueAsString(valuesMap);
}
catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
return new HttpEntity<String>(json, headers);
}
}
25 changes: 18 additions & 7 deletions backend/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,17 @@ custom:
helpText: tooltip.ignore-request-signatures
attributeName: http://shibboleth.net/ns/profiles/ignoreRequestSignatures
attributeFriendlyName: ignoreRequestSignatures
- name: postAuthenticationFlows
attributeFriendlyName: postAuthenticationFlows
displayName: label.postAuthenticationFlows
helpText: tooltip.postAuthenticationFlows
displayType: selection_list
defaultValues:
- attribute-release
- expiring-password
- terms-of-use
attributeName: http://shibboleth.net/ns/profiles/postAuthenticationFlows"
protocol: saml,oidc
- name: inboundInterceptorFlows
attributeFriendlyName: inboundInterceptorFlows
displayName: label.inboundInterceptorFlows
Expand All @@ -189,13 +200,13 @@ custom:
defaultValue: client_secret_basic, client_secret_post, client_secret_jwt, private_key_jwt
attributeName: http://shibboleth.net/ns/profiles/tokenEndpointAuthMethods
protocol: oidc
- name: postAuthenticationFlows
attributeFriendlyName: postAuthenticationFlows
displayName: label.postAuthenticationFlows
helpText: tooltip.postAuthenticationFlows
displayType: string
attributeName: http://shibboleth.net/ns/profiles/postAuthenticationFlows
protocol: oidc
# - name: postAuthenticationFlows
# attributeFriendlyName: postAuthenticationFlows
# displayName: label.postAuthenticationFlows
# helpText: tooltip.postAuthenticationFlows
# displayType: string
# attributeName: http://shibboleth.net/ns/profiles/postAuthenticationFlows
# protocol: oidc
- name: proxyCount
attributeFriendlyName: proxyCount
displayName: label.proxyCount
Expand Down

0 comments on commit 0d3cad2

Please sign in to comment.