diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/discovery/web/DiscoveryEndpoint.java b/perun-oidc-server/src/main/java/cz/muni/ics/discovery/web/DiscoveryEndpoint.java
index fffa20e04..0a85af3fe 100644
--- a/perun-oidc-server/src/main/java/cz/muni/ics/discovery/web/DiscoveryEndpoint.java
+++ b/perun-oidc-server/src/main/java/cz/muni/ics/discovery/web/DiscoveryEndpoint.java
@@ -346,7 +346,7 @@ public class DiscoveryEndpoint {
m.put("code_challenge_methods_supported", Lists.newArrayList(PKCEAlgorithm.plain.getName(), PKCEAlgorithm.S256.getName()));
- m.put("device_authorization_endpoint", baseUrl + DeviceEndpoint.URL);
+ m.put("device_authorization_endpoint", config.getIssuer(false) + DeviceEndpoint.ENDPOINT_URL);
model.addAttribute(JsonEntityView.ENTITY, m);
diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/DeviceEndpoint.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/DeviceEndpoint.java
index ebe970b47..4a15276a6 100644
--- a/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/DeviceEndpoint.java
+++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/DeviceEndpoint.java
@@ -16,34 +16,29 @@
package cz.muni.ics.oauth2.web;
-import com.google.common.collect.Sets;
import cz.muni.ics.oauth2.exception.DeviceCodeCreationException;
import cz.muni.ics.oauth2.model.ClientDetailsEntity;
import cz.muni.ics.oauth2.model.ClientWithScopes;
import cz.muni.ics.oauth2.model.DeviceCode;
-import cz.muni.ics.oauth2.model.SystemScope;
import cz.muni.ics.oauth2.service.ClientDetailsEntityService;
import cz.muni.ics.oauth2.service.DeviceCodeService;
import cz.muni.ics.oauth2.service.SystemScopeService;
import cz.muni.ics.oauth2.token.DeviceTokenGranter;
-import cz.muni.ics.oidc.server.PerunScopeClaimTranslationService;
import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import cz.muni.ics.oidc.server.userInfo.PerunUserInfo;
import cz.muni.ics.oidc.web.WebHtmlClasses;
import cz.muni.ics.oidc.web.controllers.ControllerUtils;
+import cz.muni.ics.openid.connect.service.ScopeClaimTranslationService;
import cz.muni.ics.openid.connect.service.UserInfoService;
import cz.muni.ics.openid.connect.view.HttpCodeView;
import cz.muni.ics.openid.connect.view.JsonEntityView;
import cz.muni.ics.openid.connect.view.JsonErrorView;
-import java.net.URI;
import java.net.URISyntaxException;
import java.security.Principal;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
-import java.util.LinkedHashSet;
import java.util.Map;
-import java.util.Optional;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@@ -64,10 +59,10 @@ import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.StringUtils;
-import org.springframework.web.bind.annotation.ModelAttribute;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.servlet.mvc.support.RedirectAttributes;
/**
* Implements https://tools.ietf.org/html/draft-ietf-oauth-device-flow
@@ -87,6 +82,7 @@ public class DeviceEndpoint {
public static final String APPROVE_DEVICE = "approveDevice";
public static final String THEMED_APPROVE_DEVICE = "themedApproveDevice";
public static final String DEVICE_APPROVED = "deviceApproved";
+ public static final String THEMED_DEVICE_APPROVED = "themedDeviceApproved";
// response keys
public static final String DEVICE_CODE = "device_code";
@@ -107,7 +103,6 @@ public class DeviceEndpoint {
public static final String APPROVED = "approved";
public static final String SCOPES = "scopes";
public static final String PAGE = "page";
- public static final String ACR = "acr";
public static final String ERROR = "error";
// session attributes
@@ -123,8 +118,10 @@ public class DeviceEndpoint {
// other
public static final String DEFAULT = "default";
- public static final String URL = "devicecode";
- public static final String USER_URL = "device";
+ public static final String ENDPOINT_URL = "/devicecode";
+ public static final String REQUEST_USER_CODE_URL = "/device/code";
+ public static final String CHECK_USER_CODE_URL = "/device/checkcode";
+ public static final String DEVICE_APPROVED_URL = "/device/approved";
private final ClientDetailsEntityService clientService;
private final SystemScopeService scopeService;
@@ -132,7 +129,7 @@ public class DeviceEndpoint {
private final OAuth2RequestFactory oAuth2RequestFactory;
private final PerunOidcConfig perunOidcConfig;
private final WebHtmlClasses htmlClasses;
- private final PerunScopeClaimTranslationService scopeClaimTranslationService;
+ private final ScopeClaimTranslationService scopeClaimTranslationService;
private final UserInfoService userInfoService;
@Autowired
@@ -142,9 +139,9 @@ public class DeviceEndpoint {
OAuth2RequestFactory oAuth2RequestFactory,
PerunOidcConfig perunOidcConfig,
WebHtmlClasses htmlClasses,
- PerunScopeClaimTranslationService scopeClaimTranslationService,
- UserInfoService userInfoService) {
-
+ ScopeClaimTranslationService scopeClaimTranslationService,
+ UserInfoService userInfoService)
+ {
this.clientService = clientService;
this.scopeService = scopeService;
this.deviceCodeService = deviceCodeService;
@@ -155,20 +152,16 @@ public class DeviceEndpoint {
this.userInfoService = userInfoService;
}
- @RequestMapping(
- value = "/" + URL,
- method = RequestMethod.POST,
- consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
- produces = MediaType.APPLICATION_JSON_VALUE
- )
+ @PostMapping(value = ENDPOINT_URL, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
+ produces = MediaType.APPLICATION_JSON_VALUE)
public String requestDeviceCode(@RequestParam(CLIENT_ID) String clientId,
@RequestParam(name = SCOPE, required = false) String scope,
@RequestParam(name = ACR_VALUES, required = false) String acrValues,
Map
parameters,
- ModelMap model) {
-
+ ModelMap model)
+ {
ClientWithScopes clientWithScopes = new ClientWithScopes();
- String errorViewName = handleRequest(clientId, clientWithScopes, scope, model);
+ String errorViewName = preprocessRequest(clientId, clientWithScopes, scope, model);
if (errorViewName != null) {
return errorViewName;
@@ -186,78 +179,56 @@ public class DeviceEndpoint {
response.put(DEVICE_CODE, dc.getDeviceCode());
response.put(USER_CODE, dc.getUserCode());
+ Map uriParams = new HashMap<>();
if (StringUtils.hasText(acrValues)) {
- response.put(
- VERIFICATION_URI,
- constructURI(perunOidcConfig.getConfigBean().getIssuer() + USER_URL, Map.of(ACR_VALUES, acrValues))
- );
- } else {
- response.put(VERIFICATION_URI, perunOidcConfig.getConfigBean().getIssuer() + USER_URL);
+ uriParams.put(ACR_VALUES, acrValues);
+ }
+ String uriBase = perunOidcConfig.getConfigBean().getIssuer(false) + REQUEST_USER_CODE_URL;
+ response.put(VERIFICATION_URI, constructVerificationURI(uriBase, uriParams));
+
+ if (perunOidcConfig.getConfigBean().isAllowCompleteDeviceCodeUri()) {
+ uriParams.put(USER_CODE, dc.getUserCode());
+ response.put(VERIFICATION_URI_COMPLETE, constructVerificationURI(uriBase, uriParams));
}
if (clientWithScopes.getClient().getDeviceCodeValiditySeconds() != null) {
response.put(EXPIRES_IN, clientWithScopes.getClient().getDeviceCodeValiditySeconds());
}
-
- if (perunOidcConfig.getConfigBean().isAllowCompleteDeviceCodeUri()) {
- URI verificationUriComplete = new URIBuilder(perunOidcConfig.getConfigBean().getIssuer() + USER_URL)
- .addParameter(USER_CODE, dc.getUserCode())
- .build();
-
- response.put(
- VERIFICATION_URI_COMPLETE,
- constructURI(
- perunOidcConfig.getConfigBean().getIssuer() + USER_URL,
- Map.of(ACR_VALUES, acrValues, USER_CODE, dc.getUserCode())
- )
- );
- }
model.put(JsonEntityView.ENTITY, response);
return JsonEntityView.VIEWNAME;
- } catch (DeviceCodeCreationException dcce) {
+ } catch (DeviceCodeCreationException ex) {
model.put(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
- model.put(JsonErrorView.ERROR, dcce.getError());
- model.put(JsonErrorView.ERROR_MESSAGE, dcce.getMessage());
-
+ model.put(JsonErrorView.ERROR, ex.getError());
+ model.put(JsonErrorView.ERROR_MESSAGE, ex.getMessage());
return JsonErrorView.VIEWNAME;
- } catch (URISyntaxException use) {
+ } catch (URISyntaxException ex) {
log.error("unable to build verification_uri_complete due to wrong syntax of uri components");
model.put(HttpCodeView.CODE, HttpStatus.INTERNAL_SERVER_ERROR);
-
return HttpCodeView.VIEWNAME;
}
}
@PreAuthorize("hasRole('ROLE_USER')")
- @RequestMapping(value = "/" + USER_URL, method = RequestMethod.GET)
+ @GetMapping(value = REQUEST_USER_CODE_URL)
public String requestUserCode(@RequestParam(value = USER_CODE, required = false) String userCode,
- @ModelAttribute(AUTHORIZATION_REQUEST) AuthorizationRequest authRequest,
- Principal p,
HttpServletRequest req,
- ModelMap model,
- HttpSession session) {
-
- if (!perunOidcConfig.getConfigBean().isAllowCompleteDeviceCodeUri() || userCode == null) {
- // if we don't allow the complete URI or we didn't get a user code on the way in,
- // print out a page that asks the user to enter their user code
- // user must be logged in
- return getRequestUserCodeViewName(req, model);
+ ModelMap model)
+ {
+ if (perunOidcConfig.getConfigBean().isAllowCompleteDeviceCodeUri() && StringUtils.hasText(userCode)) {
+ return verifyUserCode(userCode, req, model);
} else {
- // complete verification uri was used, we received user code directly
- // skip requesting code page
- // user must be logged in
- return readUserCode(userCode, model, p, req, session);
+ return getRequestUserCodeViewName(req, model);
}
}
@PreAuthorize("hasRole('ROLE_USER')")
- @RequestMapping(value = "/" + USER_URL + "/verify", method = RequestMethod.POST)
- public String readUserCode(@RequestParam(USER_CODE) String userCode,
- ModelMap model,
- Principal p,
- HttpServletRequest req,
- HttpSession session) {
+ @PostMapping(value = REQUEST_USER_CODE_URL)
+ public String verifyUserCode(@RequestParam(value = USER_CODE) String userCode,
+ HttpServletRequest req,
+ ModelMap model)
+ {
+ model.put(USER_CODE, userCode);
DeviceCode dc = deviceCodeService.lookUpByUserCode(userCode);
@@ -266,30 +237,49 @@ public class DeviceEndpoint {
return errorViewName;
}
+ HttpSession session = req.getSession();
+ session.setAttribute(DEVICE_CODE_SESSION_ATTRIBUTE, dc);
+
+ return "redirect:" + CHECK_USER_CODE_URL + '?' + USER_CODE + '=' + userCode;
+ }
+
+ @PreAuthorize("hasRole('ROLE_USER')")
+ @GetMapping(value = CHECK_USER_CODE_URL)
+ public String startApproveDevice(@RequestParam(USER_CODE) String userCode,
+ ModelMap model,
+ Principal p,
+ HttpServletRequest req)
+ {
+ DeviceCode dc = deviceCodeService.lookUpByUserCode(userCode);
+ model.put(USER_CODE, userCode);
+
+ String errorViewName = checkDeviceCodeIsValid(dc, req, model);
+ if (errorViewName != null) {
+ return errorViewName;
+ }
+
ClientDetailsEntity client = clientService.loadClientByClientId(dc.getClientId());
model.put(CLIENT, client);
model.put(DC, dc);
- model.put(SCOPES, getSortedScopes(dc));
+ HttpSession session = req.getSession();
AuthorizationRequest authorizationRequest = oAuth2RequestFactory.createAuthorizationRequest(dc.getRequestParameters());
-
session.setAttribute(AUTHORIZATION_REQUEST, authorizationRequest);
- session.setAttribute(DEVICE_CODE_SESSION_ATTRIBUTE, dc);
- return getApproveDeviceViewName(model, p, req, (DeviceCode) model.get(DC));
+ return getApproveDeviceViewName(model, p, req, dc);
}
@PreAuthorize("hasRole('ROLE_USER')")
- @RequestMapping(value = "/" + USER_URL + "/approve", method = RequestMethod.POST)
- public String approveDevice(@RequestParam(USER_CODE) String userCode,
- @RequestParam(value = USER_OAUTH_APPROVAL) Boolean approve,
- Principal p,
- HttpServletRequest req,
- ModelMap model,
- Authentication auth,
- HttpSession session) {
-
+ @PostMapping(value = DEVICE_APPROVED_URL)
+ public String processApproveDevice(@RequestParam(USER_CODE) String userCode,
+ @RequestParam(value = USER_OAUTH_APPROVAL) Boolean approve,
+ Principal p,
+ HttpServletRequest req,
+ ModelMap model,
+ Authentication auth)
+ {
+ HttpSession session = req.getSession();
AuthorizationRequest authorizationRequest = (AuthorizationRequest) session.getAttribute(AUTHORIZATION_REQUEST);
if (authorizationRequest == null) {
throw new IllegalArgumentException("Authorization request not found in the session");
@@ -325,15 +315,13 @@ public class DeviceEndpoint {
OAuth2Request o2req = oAuth2RequestFactory.createOAuth2Request(authorizationRequest);
OAuth2Authentication o2Auth = new OAuth2Authentication(o2req, auth);
- DeviceCode approvedCode = deviceCodeService.approveDeviceCode(dc, o2Auth);
+ deviceCodeService.approveDeviceCode(dc, o2Auth);
- model.put(SCOPES, getSortedScopes(dc));
model.put(APPROVED, true);
-
- return DEVICE_APPROVED;
+ return getDeviceApprovedViewName(req, model);
}
- private String handleRequest(String clientId, ClientWithScopes clientWithScopes, String scope, ModelMap model) {
+ private String preprocessRequest(String clientId, ClientWithScopes clientWithScopes, String scope, ModelMap model) {
ClientDetailsEntity client;
try {
@@ -360,10 +348,9 @@ public class DeviceEndpoint {
Set allowedScopes = client.getScope();
if (!scopeService.scopesMatch(allowedScopes, requestedScopes)) {
- log.error("Client asked for {} but is allowed {}", requestedScopes, allowedScopes);
+ log.error("Client asked for {} but is allowed to request only {}", requestedScopes, allowedScopes);
model.put(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
model.put(JsonErrorView.ERROR, INVALID_SCOPE);
-
return JsonErrorView.VIEWNAME;
}
@@ -402,18 +389,25 @@ public class DeviceEndpoint {
ControllerUtils.setPageOptions(model, req, htmlClasses, perunOidcConfig);
model.put(PAGE, REQUEST_USER_CODE);
- String shibAuthnContextClass = "";
-
- model.put(ACR, shibAuthnContextClass);
return THEMED_REQUEST_USER_CODE;
}
+ private String getDeviceApprovedViewName(HttpServletRequest req, ModelMap model) {
+ if (perunOidcConfig.getTheme().equalsIgnoreCase(DEFAULT)) {
+ return DEVICE_APPROVED;
+ }
+
+ ControllerUtils.setPageOptions(model, req, htmlClasses, perunOidcConfig);
+ model.put(PAGE, DEVICE_APPROVED);
+ return THEMED_DEVICE_APPROVED;
+ }
+
private String getApproveDeviceViewName(ModelMap model, Principal p, HttpServletRequest req, DeviceCode dc) {
if (perunOidcConfig.getTheme().equalsIgnoreCase(DEFAULT)) {
+ model.put(SCOPES, ControllerUtils.getSortedScopes(dc.getScope(), scopeService));
return APPROVE_DEVICE;
}
- model.remove(SCOPES);
ClientDetailsEntity client = (ClientDetailsEntity) model.get(CLIENT);
PerunUserInfo user = (PerunUserInfo) userInfoService.getByUsernameAndClientId(
@@ -428,39 +422,15 @@ public class DeviceEndpoint {
return THEMED_APPROVE_DEVICE;
}
- private Set getSortedScopes(DeviceCode dc) {
- Set scopes = scopeService.fromStrings(dc.getScope());
-
- Set sortedScopes = new LinkedHashSet<>(scopes.size());
- Set systemScopes = scopeService.getAll();
-
- for (SystemScope s : systemScopes) {
- if (scopes.contains(s)) {
- sortedScopes.add(s);
- }
- }
-
- sortedScopes.addAll(Sets.difference(scopes, systemScopes));
- return sortedScopes;
- }
-
- private String constructURI(String uri, Map params) {
- if (params.isEmpty()) {
+ private String constructVerificationURI(String uri, Map params) throws URISyntaxException {
+ if (params == null || params.isEmpty()) {
return uri;
}
- StringBuilder uriBuilder = new StringBuilder(uri);
-
- if (!uri.contains("?")) {
- Optional key = params.keySet().stream().findFirst();
- uriBuilder.append("?").append(key).append("=").append(params.get(key));
- params.remove(key);
+ URIBuilder builder = new URIBuilder(uri);
+ for (Map.Entry param: params.entrySet()) {
+ builder.addParameter(param.getKey(), param.getValue());
}
-
- for (Map.Entry entry : params.entrySet()) {
- uriBuilder.append("&").append(entry.getKey()).append("=").append(entry.getValue());
- }
-
- return uriBuilder.toString();
+ return builder.build().toString();
}
}
diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/OAuthConfirmationController.java b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/OAuthConfirmationController.java
index 71755f1ce..6f646400f 100644
--- a/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/OAuthConfirmationController.java
+++ b/perun-oidc-server/src/main/java/cz/muni/ics/oauth2/web/OAuthConfirmationController.java
@@ -166,7 +166,7 @@ public class OAuthConfirmationController {
model.put(CLIENT, client);
model.put(REDIRECT_URI, authRequest.getRedirectUri());
- Set sortedScopes = getSortedScopes(authRequest);
+ Set sortedScopes = ControllerUtils.getSortedScopes(authRequest.getScope(), scopeService);
model.put(SCOPES, sortedScopes);
// get the userinfo claims for each scope
@@ -212,26 +212,6 @@ public class OAuthConfirmationController {
}
}
- private Set getSortedScopes(AuthorizationRequest authRequest) {
- // pre-process the scopes
- Set scopes = scopeService.fromStrings(authRequest.getScope());
-
- Set sortedScopes = new LinkedHashSet<>(scopes.size());
- Set systemScopes = scopeService.getAll();
-
- // sort scopes for display based on the inherent order of system scopes
- for (SystemScope s : systemScopes) {
- if (scopes.contains(s)) {
- sortedScopes.add(s);
- }
- }
-
- // add in any scopes that aren't system scopes to the end of the list
- sortedScopes.addAll(Sets.difference(scopes, systemScopes));
-
- return sortedScopes;
- }
-
private Map> getClaimsForScopes(Principal p, Set sortedScopes) {
UserInfo user = userInfoService.getByUsername(p.getName());
Map> claimsForScopes = new HashMap<>();
diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/SamlInvalidateSessionFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/SamlInvalidateSessionFilter.java
index be4a5b02f..ee3651e96 100644
--- a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/SamlInvalidateSessionFilter.java
+++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/saml/SamlInvalidateSessionFilter.java
@@ -1,5 +1,7 @@
package cz.muni.ics.oidc.saml;
+import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.AUTHORIZE_REQ_PATTERN;
+import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.DEVICE_APPROVE_REQ_PATTERN;
import static org.springframework.http.HttpHeaders.REFERER;
import java.io.IOException;
@@ -16,25 +18,30 @@ import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+import org.springframework.security.web.util.matcher.OrRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;
@Slf4j
public class SamlInvalidateSessionFilter extends GenericFilterBean {
- private final AntPathRequestMatcher matcher;
+ private static final RequestMatcher AUTHORIZE_MATCHER = new AntPathRequestMatcher(AUTHORIZE_REQ_PATTERN);
+ private static final RequestMatcher AUTHORIZE_ALL_MATCHER = new AntPathRequestMatcher(AUTHORIZE_REQ_PATTERN + "/**");
+ private static final RequestMatcher DEVICE_CODE_MATCHER = new AntPathRequestMatcher(DEVICE_APPROVE_REQ_PATTERN);
+ private static final RequestMatcher DEVICE_CODE_ALL_MATCHER = new AntPathRequestMatcher(DEVICE_APPROVE_REQ_PATTERN + "/**");
+ private static final RequestMatcher MATCHER = new OrRequestMatcher(
+ Arrays.asList(AUTHORIZE_MATCHER, AUTHORIZE_ALL_MATCHER, DEVICE_CODE_MATCHER, DEVICE_CODE_ALL_MATCHER));
private final SecurityContextLogoutHandler contextLogoutHandler;
private final List internalReferrers = new ArrayList<>();
- public SamlInvalidateSessionFilter(String pattern,
- String idpEntityId,
+ public SamlInvalidateSessionFilter(String idpEntityId,
String oidcIssuer,
String proxySpEntityId,
SecurityContextLogoutHandler contextLogoutHandler,
String[] internalReferrers)
{
- this.matcher = new AntPathRequestMatcher(pattern);
if (StringUtils.hasText(idpEntityId)) {
this.internalReferrers.add(idpEntityId);
}
@@ -60,9 +67,10 @@ public class SamlInvalidateSessionFilter extends GenericFilterBean {
{
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
- if (matcher.matches(req)) {
+ if (MATCHER.matches(req)) {
+ boolean isDeviceCodeFlow = DEVICE_CODE_MATCHER.matches(req) || DEVICE_CODE_ALL_MATCHER.matches(req);
String referer = req.getHeader(REFERER);
- if (!isInternalReferer(referer)) {
+ if (!isInternalReferer(referer, !isDeviceCodeFlow)) {
log.debug("Got external referer, clear session to reauthenticate");
contextLogoutHandler.logout(req, res, null);
}
@@ -70,9 +78,9 @@ public class SamlInvalidateSessionFilter extends GenericFilterBean {
chain.doFilter(req, res);
}
- private boolean isInternalReferer(String referer) {
+ private boolean isInternalReferer(String referer, boolean emptyRefererAsInternal) {
if (!StringUtils.hasText(referer)) { // no referer, consider as internal
- return true;
+ return emptyRefererAsInternal;
}
for (String internal : internalReferrers) {
if (referer.startsWith(internal)) {
diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/CallPerunFiltersFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/CallPerunFiltersFilter.java
index c5fb1be71..a4ce091d9 100644
--- a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/CallPerunFiltersFilter.java
+++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/CallPerunFiltersFilter.java
@@ -1,5 +1,8 @@
package cz.muni.ics.oidc.server.filters;
+import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.AUTHORIZE_REQ_PATTERN;
+import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.DEVICE_CHECK_CODE_REQ_PATTERN;
+
import cz.muni.ics.oauth2.model.ClientDetailsEntity;
import cz.muni.ics.oauth2.service.ClientDetailsEntityService;
import cz.muni.ics.oidc.BeanUtil;
@@ -8,6 +11,7 @@ import cz.muni.ics.oidc.models.PerunUser;
import cz.muni.ics.oidc.saml.SamlProperties;
import cz.muni.ics.oidc.server.adapters.PerunAdapter;
import java.io.IOException;
+import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import javax.annotation.PostConstruct;
@@ -19,6 +23,9 @@ import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+import org.springframework.security.web.util.matcher.OrRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;
@@ -31,6 +38,13 @@ import org.springframework.web.filter.GenericFilterBean;
@Slf4j
public class CallPerunFiltersFilter extends GenericFilterBean {
+ private static final RequestMatcher AUTHORIZE_MATCHER = new AntPathRequestMatcher(AUTHORIZE_REQ_PATTERN);
+ private static final RequestMatcher AUTHORIZE_ALL_MATCHER = new AntPathRequestMatcher(AUTHORIZE_REQ_PATTERN + "/**");
+ private static final RequestMatcher DEVICE_CODE_MATCHER = new AntPathRequestMatcher(DEVICE_CHECK_CODE_REQ_PATTERN);
+ private static final RequestMatcher DEVICE_CODE_ALL_MATCHER = new AntPathRequestMatcher(DEVICE_CHECK_CODE_REQ_PATTERN + "/**");
+ private static final RequestMatcher MATCHER = new OrRequestMatcher(
+ Arrays.asList(AUTHORIZE_MATCHER, AUTHORIZE_ALL_MATCHER, DEVICE_CODE_MATCHER, DEVICE_CODE_ALL_MATCHER));
+
@Autowired
private Properties coreProperties;
@@ -60,25 +74,30 @@ public class CallPerunFiltersFilter extends GenericFilterBean {
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException
{
- List filters = perunFiltersContext.getFilters();
- if (filters != null && !filters.isEmpty()) {
- HttpServletRequest request = (HttpServletRequest) servletRequest;
- ClientDetailsEntity client = FiltersUtils.extractClientFromRequest(request, authRequestFactory,
- clientDetailsEntityService);
- Facility facility = null;
- if (client != null && StringUtils.hasText(client.getClientId())) {
- try {
- facility = perunAdapter.getFacilityByClientId(client.getClientId());
- } catch (Exception e) {
- log.warn("{} - could not fetch facility for client_id '{}'",
- CallPerunFiltersFilter.class.getSimpleName(), client.getClientId(), e);
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ if (!MATCHER.matches(request)) {
+ log.debug("Custom filters have been skipped, did not match '/authorize' nor '/device/code' request");
+ } else {
+ List filters = perunFiltersContext.getFilters();
+ if (filters != null && !filters.isEmpty()) {
+ ClientDetailsEntity client = FiltersUtils.extractClientFromRequest(request, authRequestFactory,
+ clientDetailsEntityService);
+ Facility facility = null;
+ if (client != null && StringUtils.hasText(client.getClientId())) {
+ try {
+ facility = perunAdapter.getFacilityByClientId(client.getClientId());
+ } catch (Exception e) {
+ log.warn("{} - could not fetch facility for client_id '{}'",
+ CallPerunFiltersFilter.class.getSimpleName(), client.getClientId(), e);
+ }
}
- }
- PerunUser user = FiltersUtils.getPerunUser(request, perunAdapter, samlProperties.getUserIdentifierAttribute());
- FilterParams params = new FilterParams(client, facility, user);
- for (PerunRequestFilter filter : filters) {
- if (!filter.doFilter(servletRequest, servletResponse, params)) {
- return;
+ PerunUser user = FiltersUtils.getPerunUser(request, perunAdapter,
+ samlProperties.getUserIdentifierAttribute());
+ FilterParams params = new FilterParams(client, facility, user);
+ for (PerunRequestFilter filter : filters) {
+ if (!filter.doFilter(servletRequest, servletResponse, params)) {
+ return;
+ }
}
}
}
diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/FiltersUtils.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/FiltersUtils.java
index 8392efed9..43964205d 100644
--- a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/FiltersUtils.java
+++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/FiltersUtils.java
@@ -1,9 +1,10 @@
package cz.muni.ics.oidc.server.filters;
+import static cz.muni.ics.oauth2.web.DeviceEndpoint.DEVICE_CODE_SESSION_ATTRIBUTE;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_FORCE_AUTHN;
-import com.google.common.base.Strings;
import cz.muni.ics.oauth2.model.ClientDetailsEntity;
+import cz.muni.ics.oauth2.model.DeviceCode;
import cz.muni.ics.oauth2.service.ClientDetailsEntityService;
import cz.muni.ics.oidc.models.Facility;
import cz.muni.ics.oidc.models.PerunAttributeValue;
@@ -20,13 +21,9 @@ import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.security.core.userdetails.User;
-import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.providers.ExpiringUsernameAuthenticationToken;
import org.springframework.security.saml.SAMLCredential;
-import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
-import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.StringUtils;
/**
@@ -37,8 +34,6 @@ import org.springframework.util.StringUtils;
@Slf4j
public class FiltersUtils {
- private static final RequestMatcher requestMatcher = new AntPathRequestMatcher(PerunFilterConstants.AUTHORIZE_REQ_PATTERN);
-
/**
* Create map of request params in format key = name, value = paramValue.
*
@@ -69,21 +64,29 @@ public class FiltersUtils {
OAuth2RequestFactory authRequestFactory,
ClientDetailsEntityService clientService)
{
- if (!requestMatcher.matches(request) || request.getParameter("response_type") == null) {
+ if (request.getParameter("response_type") == null
+ && request.getSession() == null
+ && request.getSession().getAttribute(DEVICE_CODE_SESSION_ATTRIBUTE) == null
+ ) {
return null;
}
- AuthorizationRequest authRequest = authRequestFactory.createAuthorizationRequest(
- FiltersUtils.createRequestMap(request.getParameterMap()));
+ String clientId;
+ if (request.getSession() != null && request.getSession().getAttribute(DEVICE_CODE_SESSION_ATTRIBUTE) != null) {
+ clientId = ((DeviceCode) request.getSession().getAttribute(DEVICE_CODE_SESSION_ATTRIBUTE)).getClientId();
+ } else {
+ clientId = authRequestFactory.createAuthorizationRequest(
+ FiltersUtils.createRequestMap(request.getParameterMap())).getClientId();
+ }
ClientDetailsEntity client;
- if (Strings.isNullOrEmpty(authRequest.getClientId())) {
+ if (!StringUtils.hasText(clientId)) {
log.debug("cannot extract client - ClientID is null or empty");
return null;
}
- client = clientService.loadClientByClientId(authRequest.getClientId());
- if (Strings.isNullOrEmpty(client.getClientName())) {
+ client = clientService.loadClientByClientId(clientId);
+ if (!StringUtils.hasText(client.getClientName())) {
log.warn("cannot extract clientName for the clientID '{}'", client.getClientId());
return null;
}
@@ -207,11 +210,11 @@ public class FiltersUtils {
/**
* Redirect user to the unapproved page.
- * @param request original request object
+ * @param base Base URL
* @param response response object
* @param clientId identifier of the service
*/
- public static void redirectUnapproved(HttpServletRequest request, HttpServletResponse response, String clientId, String redirectMapping)
+ public static void redirectUnapproved(String base, HttpServletResponse response, String clientId, String redirectMapping)
{
// cannot register, redirect to unapproved
Map params = new HashMap<>();
@@ -219,8 +222,7 @@ public class FiltersUtils {
params.put("client_id", clientId);
}
- String redirectUrl = ControllerUtils.createRedirectUrl(request, PerunFilterConstants.AUTHORIZE_REQ_PATTERN,
- redirectMapping, params);
+ String redirectUrl = ControllerUtils.createRedirectUrl(base, redirectMapping, params);
response.reset();
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
response.setHeader("Location", redirectUrl);
@@ -228,7 +230,7 @@ public class FiltersUtils {
/**
* Redirect user to the correct page when cannot access the service based on membership.
- * @param request Request object
+ * @param base base URL
* @param response Response object
* @param facility Facility representing the client
* @param user User accessing the service
@@ -237,7 +239,7 @@ public class FiltersUtils {
* @param facilityAttributes Actual facility attributes
* @param perunAdapter Adapter to call Perun
*/
- public static void redirectUserCannotAccess(HttpServletRequest request,
+ public static void redirectUserCannotAccess(String base,
HttpServletResponse response,
Facility facility,
PerunUser user,
@@ -263,7 +265,7 @@ public class FiltersUtils {
if (facilityAttributes.get(facilityAttrsConfig.getDynamicRegistrationAttr()).valueAsBoolean()) {
// redirect to registration form
- FiltersUtils.redirectToRegistrationForm(request, response, clientIdentifier, facility, user);
+ FiltersUtils.redirectToRegistrationForm(base, response, clientIdentifier, facility, user);
return;
}
}
@@ -271,7 +273,7 @@ public class FiltersUtils {
// cannot register, redirect to unapproved
log.debug("user cannot register to obtain access, redirecting user '{}' to unapproved page", user);
- FiltersUtils.redirectUnapproved(request, response, clientIdentifier, redirectUrl);
+ FiltersUtils.redirectUnapproved(base, response, clientIdentifier, redirectUrl);
}
public static String fillStringMandatoryProperty(String propertyName,
@@ -286,13 +288,13 @@ public class FiltersUtils {
return filled;
}
- private static void redirectToRegistrationForm(HttpServletRequest request, HttpServletResponse response,
+ private static void redirectToRegistrationForm(String base, HttpServletResponse response,
String clientIdentifier, Facility facility, PerunUser user) {
Map params = new HashMap<>();
params.put("client_id", clientIdentifier);
params.put("facility_id", facility.getId().toString());
params.put("user_id", String.valueOf(user.getId()));
- String redirectUrl = ControllerUtils.createRedirectUrl(request, PerunFilterConstants.AUTHORIZE_REQ_PATTERN,
+ String redirectUrl = ControllerUtils.createRedirectUrl(base,
PerunUnapprovedRegistrationController.REGISTRATION_CONTINUE_MAPPING, params);
log.debug("redirecting user '{}' to the registration form URL: {}", user, redirectUrl);
response.reset();
diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunFilterConstants.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunFilterConstants.java
index 8469ed180..23a1f7426 100644
--- a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunFilterConstants.java
+++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunFilterConstants.java
@@ -12,9 +12,8 @@ import java.util.Map;
public class PerunFilterConstants {
public static final String AUTHORIZE_REQ_PATTERN = "/authorize";
- public static final String SHIB_IDENTITY_PROVIDER = "Shib-Identity-Provider";
- public static final String SHIB_AUTHN_CONTEXT_CLASS = "Shib-AuthnContext-Class";
- public static final String SHIB_AUTHN_CONTEXT_METHOD = "Shib-Authentication-Method";
+ public static final String DEVICE_APPROVE_REQ_PATTERN = "/device/code";
+ public static final String DEVICE_CHECK_CODE_REQ_PATTERN = "/device/checkcode";
public static final String PARAM_CLIENT_ID = "client_id";
public static final String PARAM_SCOPE = "scope";
diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunRequestFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunRequestFilter.java
index 157296e01..3d5503c97 100644
--- a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunRequestFilter.java
+++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/PerunRequestFilter.java
@@ -1,6 +1,8 @@
package cz.muni.ics.oidc.server.filters;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.AUTHORIZE_REQ_PATTERN;
+import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.DEVICE_APPROVE_REQ_PATTERN;
+import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.DEVICE_CHECK_CODE_REQ_PATTERN;
import java.io.IOException;
import java.util.Arrays;
@@ -11,6 +13,7 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
@@ -42,8 +45,6 @@ public abstract class PerunRequestFilter {
private static final String CLIENT_IDS = "clientIds";
private static final String SUBS = "subs";
- private static final RequestMatcher requestMatcher = new AntPathRequestMatcher(AUTHORIZE_REQ_PATTERN);
-
private final String filterName;
private Set clientIds = new HashSet<>();
private Set subs = new HashSet<>();
@@ -77,11 +78,6 @@ public abstract class PerunRequestFilter {
public boolean doFilter(ServletRequest req, ServletResponse res, FilterParams params) throws IOException {
HttpServletRequest request = (HttpServletRequest) req;
- // skip everything that's not an authorize URL
- if (!requestMatcher.matches(request)) {
- log.debug("{} - filter has been skipped, did not match '/authorize' the request", filterName);
- return true;
- }
if (!skip(request)) {
log.trace("{} - executing filter", filterName);
return this.process(req, res, params);
diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunAuthorizationFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunAuthorizationFilter.java
index aa1d22801..f5679b096 100644
--- a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunAuthorizationFilter.java
+++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunAuthorizationFilter.java
@@ -6,6 +6,7 @@ import cz.muni.ics.oidc.models.PerunAttributeValue;
import cz.muni.ics.oidc.models.PerunUser;
import cz.muni.ics.oidc.server.adapters.PerunAdapter;
import cz.muni.ics.oidc.server.configurations.FacilityAttrsConfig;
+import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import cz.muni.ics.oidc.server.filters.FilterParams;
import cz.muni.ics.oidc.server.filters.FiltersUtils;
import cz.muni.ics.oidc.server.filters.PerunRequestFilter;
@@ -35,6 +36,7 @@ public class PerunAuthorizationFilter extends PerunRequestFilter {
private final PerunAdapter perunAdapter;
private final FacilityAttrsConfig facilityAttrsConfig;
private final String filterName;
+ private final PerunOidcConfig config;
public PerunAuthorizationFilter(PerunRequestFilterParams params) {
super(params);
@@ -42,6 +44,7 @@ public class PerunAuthorizationFilter extends PerunRequestFilter {
this.perunAdapter = beanUtil.getBean(PerunAdapter.class);
this.facilityAttrsConfig = beanUtil.getBean(FacilityAttrsConfig.class);
this.filterName = params.getFilterName();
+ this.config = beanUtil.getBean(PerunOidcConfig.class);
}
@Override
@@ -81,7 +84,7 @@ public class PerunAuthorizationFilter extends PerunRequestFilter {
log.info("{} - user allowed to access the service", filterName);
return true;
} else {
- FiltersUtils.redirectUserCannotAccess(request, response, facility, user, clientIdentifier,
+ FiltersUtils.redirectUserCannotAccess(config.getConfigBean().getIssuer(), response, facility, user, clientIdentifier,
facilityAttrsConfig, facilityAttributes, perunAdapter,
PerunUnapprovedController.UNAPPROVED_AUTHORIZATION);
return false;
diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunIsCesnetEligibleFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunIsCesnetEligibleFilter.java
index bd51b8ed9..a51236965 100644
--- a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunIsCesnetEligibleFilter.java
+++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunIsCesnetEligibleFilter.java
@@ -11,6 +11,7 @@ import cz.muni.ics.oidc.BeanUtil;
import cz.muni.ics.oidc.models.PerunAttributeValue;
import cz.muni.ics.oidc.models.PerunUser;
import cz.muni.ics.oidc.server.adapters.PerunAdapter;
+import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import cz.muni.ics.oidc.server.filters.FilterParams;
import cz.muni.ics.oidc.server.filters.FiltersUtils;
import cz.muni.ics.oidc.server.filters.PerunFilterConstants;
@@ -58,12 +59,14 @@ public class PerunIsCesnetEligibleFilter extends PerunRequestFilter {
private final int validityPeriod;
/* END OF CONFIGURATION PROPERTIES */
+ private final PerunOidcConfig config;
private final PerunAdapter perunAdapter;
private final String filterName;
public PerunIsCesnetEligibleFilter(PerunRequestFilterParams params) {
super(params);
BeanUtil beanUtil = params.getBeanUtil();
+ this.config = beanUtil.getBean(PerunOidcConfig.class);
this.perunAdapter = beanUtil.getBean(PerunAdapter.class);
this.isCesnetEligibleAttrName = params.getProperty(IS_CESNET_ELIGIBLE_ATTR_NAME);
this.triggerScope = params.getProperty(IS_CESNET_ELIGIBLE_SCOPE);
@@ -132,7 +135,7 @@ public class PerunIsCesnetEligibleFilter extends PerunRequestFilter {
params.put(PARAM_TARGET, targetURL);
params.put(PARAM_REASON, reason);
- String redirectUrl = ControllerUtils.createRedirectUrl(req, PerunFilterConstants.AUTHORIZE_REQ_PATTERN,
+ String redirectUrl = ControllerUtils.createRedirectUrl(config.getConfigBean().getIssuer(),
PerunUnapprovedController.UNAPPROVED_IS_CESNET_ELIGIBLE_MAPPING, params);
log.debug("{} - redirecting user to unapproved: URL '{}'", filterName, redirectUrl);
res.reset();
diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunIsTestSpFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunIsTestSpFilter.java
index 1802918ea..d027eed43 100644
--- a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunIsTestSpFilter.java
+++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/PerunIsTestSpFilter.java
@@ -7,6 +7,7 @@ import cz.muni.ics.oidc.BeanUtil;
import cz.muni.ics.oidc.models.Facility;
import cz.muni.ics.oidc.models.PerunAttributeValue;
import cz.muni.ics.oidc.server.adapters.PerunAdapter;
+import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import cz.muni.ics.oidc.server.filters.FilterParams;
import cz.muni.ics.oidc.server.filters.FiltersUtils;
import cz.muni.ics.oidc.server.filters.PerunFilterConstants;
@@ -43,6 +44,7 @@ public class PerunIsTestSpFilter extends PerunRequestFilter {
private final String isTestSpAttrName;
private final PerunAdapter perunAdapter;
private final String filterName;
+ private final PerunOidcConfig config;
public PerunIsTestSpFilter(PerunRequestFilterParams params) {
super(params);
@@ -50,6 +52,7 @@ public class PerunIsTestSpFilter extends PerunRequestFilter {
this.perunAdapter = beanUtil.getBean(PerunAdapter.class);
this.isTestSpAttrName = params.getProperty(IS_TEST_SP_ATTR_NAME);
this.filterName = params.getFilterName();
+ this.config = beanUtil.getBean(PerunOidcConfig.class);
}
@Override
@@ -95,7 +98,7 @@ public class PerunIsTestSpFilter extends PerunRequestFilter {
Map params = new HashMap<>();
params.put(PARAM_TARGET, targetURL);
- String redirectUrl = ControllerUtils.createRedirectUrl(req, PerunFilterConstants.AUTHORIZE_REQ_PATTERN,
+ String redirectUrl = ControllerUtils.createRedirectUrl(config.getConfigBean().getIssuer(),
IsTestSpController.MAPPING, params);
log.debug("{} - redirecting user to testSP warning page: {}", filterName, redirectUrl);
res.reset();
diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/ValidUserFilter.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/ValidUserFilter.java
index 408644400..bf05d8c69 100644
--- a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/ValidUserFilter.java
+++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/server/filters/impl/ValidUserFilter.java
@@ -6,6 +6,7 @@ import cz.muni.ics.oidc.models.PerunAttributeValue;
import cz.muni.ics.oidc.models.PerunUser;
import cz.muni.ics.oidc.server.adapters.PerunAdapter;
import cz.muni.ics.oidc.server.configurations.FacilityAttrsConfig;
+import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import cz.muni.ics.oidc.server.filters.FilterParams;
import cz.muni.ics.oidc.server.filters.FiltersUtils;
import cz.muni.ics.oidc.server.filters.PerunRequestFilter;
@@ -66,6 +67,7 @@ public class ValidUserFilter extends PerunRequestFilter {
private final PerunAdapter perunAdapter;
private final FacilityAttrsConfig facilityAttrsConfig;
private final String filterName;
+ private final PerunOidcConfig config;
public ValidUserFilter(PerunRequestFilterParams params) {
super(params);
@@ -80,6 +82,7 @@ public class ValidUserFilter extends PerunRequestFilter {
this.prodEnvGroups = this.getIdsFromParam(params, PROD_ENV_GROUPS);
this.prodEnvVos = this.getIdsFromParam(params, PROD_ENV_VOS);
this.filterName = params.getFilterName();
+ this.config = beanUtil.getBean(PerunOidcConfig.class);
}
@Override
@@ -103,7 +106,7 @@ public class ValidUserFilter extends PerunRequestFilter {
return true;
}
- if (!checkMemberValidInGroupsAndVos(user, facility, request, response, params, allEnvVos, allEnvGroups,
+ if (!checkMemberValidInGroupsAndVos(user, facility, response, params, allEnvVos, allEnvGroups,
PerunUnapprovedController.UNAPPROVED_NOT_IN_MANDATORY_VOS_GROUPS)) {
return false;
}
@@ -118,7 +121,7 @@ public class ValidUserFilter extends PerunRequestFilter {
additionalVos.addAll(testEnvVos);
additionalGroups.addAll(testEnvGroups);
- if (!checkMemberValidInGroupsAndVos(user, facility, request, response, params, additionalVos,
+ if (!checkMemberValidInGroupsAndVos(user, facility, response, params, additionalVos,
additionalGroups, PerunUnapprovedController.UNAPPROVED_NOT_IN_TEST_VOS_GROUPS)) {
return false;
}
@@ -126,7 +129,7 @@ public class ValidUserFilter extends PerunRequestFilter {
additionalVos.addAll(prodEnvVos);
additionalGroups.addAll(prodEnvGroups);
- if (!checkMemberValidInGroupsAndVos(user, facility, request, response, params, additionalVos,
+ if (!checkMemberValidInGroupsAndVos(user, facility, response, params, additionalVos,
additionalGroups, PerunUnapprovedController.UNAPPROVED_NOT_IN_PROD_VOS_GROUPS)) {
return false;
}
@@ -153,7 +156,6 @@ public class ValidUserFilter extends PerunRequestFilter {
private boolean checkMemberValidInGroupsAndVos(
PerunUser user,
Facility facility,
- HttpServletRequest request,
HttpServletResponse response,
FilterParams params,
Set vos,
@@ -168,8 +170,8 @@ public class ValidUserFilter extends PerunRequestFilter {
Map facilityAttributes = perunAdapter.getFacilityAttributeValues(
facility, facilityAttrsConfig.getMembershipAttrNames());
- FiltersUtils.redirectUserCannotAccess(request, response, facility, user, params.getClientIdentifier(),
- facilityAttrsConfig, facilityAttributes, perunAdapter, redirectUrl);
+ FiltersUtils.redirectUserCannotAccess(config.getConfigBean().getIssuer(), response, facility, user,
+ params.getClientIdentifier(), facilityAttrsConfig, facilityAttributes, perunAdapter, redirectUrl);
return false;
}
diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/ControllerUtils.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/ControllerUtils.java
index ad6d20de9..b2d0f9fcc 100644
--- a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/ControllerUtils.java
+++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/ControllerUtils.java
@@ -84,23 +84,24 @@ public class ControllerUtils {
/**
* Create redirect URL.
*
- * @param request Request object
- * @param removedPart Part of URL to be removed
- * @param pathPart What to include as Path
- * @param params Map object of parameters
+ * @param base Base of URL, might include some path already
+ * @param path What to include as Path
+ * @param params Map object of parameters
* @return Modified redirect URL
*/
- public static String createRedirectUrl(HttpServletRequest request, String removedPart,
- String pathPart, Map params) {
- String baseUrl = request.getRequestURL().toString();
- int endIndex = baseUrl.indexOf(removedPart);
- if (endIndex > 1) {
- baseUrl = baseUrl.substring(0, endIndex);
- }
-
+ public static String createRedirectUrl(String base,
+ String path,
+ Map params)
+ {
StringBuilder builder = new StringBuilder();
- builder.append(baseUrl);
- builder.append(pathPart);
+ if (!base.endsWith("/")) {
+ base += '/';
+ }
+ builder.append(base);
+ if (path.startsWith("/")) {
+ path = path.substring(1);
+ }
+ builder.append(path);
if (!params.isEmpty()) {
builder.append('?');
for (Map.Entry entry : params.entrySet()) {
@@ -292,4 +293,20 @@ public class ControllerUtils {
}
}
+ public static Set getSortedScopes(Set requestedScopes, SystemScopeService scopeService) {
+ Set scopes = scopeService.fromStrings(requestedScopes);
+
+ Set sortedScopes = new LinkedHashSet<>(scopes.size());
+ Set systemScopes = scopeService.getAll();
+
+ for (SystemScope s : systemScopes) {
+ if (scopes.contains(s)) {
+ sortedScopes.add(s);
+ }
+ }
+
+ sortedScopes.addAll(Sets.difference(scopes, systemScopes));
+ return sortedScopes;
+ }
+
}
diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/PerunUnapprovedRegistrationController.java b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/PerunUnapprovedRegistrationController.java
index 3d99478b8..e1ec8d437 100644
--- a/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/PerunUnapprovedRegistrationController.java
+++ b/perun-oidc-server/src/main/java/cz/muni/ics/oidc/web/controllers/PerunUnapprovedRegistrationController.java
@@ -91,7 +91,7 @@ public class PerunUnapprovedRegistrationController {
log.debug("groupsForReg: {}", groupsForRegistration);
if (groupsForRegistration.isEmpty()) {
- String redirectUrl = ControllerUtils.createRedirectUrl(request, REGISTRATION_FORM_MAPPING,
+ String redirectUrl = ControllerUtils.createRedirectUrl(perunOidcConfig.getConfigBean().getIssuer(),
PerunUnapprovedController.UNAPPROVED_MAPPING, Collections.singletonMap("client_id", clientId));
response.reset();
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
diff --git a/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/ConfigurationPropertiesBean.java b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/ConfigurationPropertiesBean.java
index 9021fca32..911305e59 100644
--- a/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/ConfigurationPropertiesBean.java
+++ b/perun-oidc-server/src/main/java/cz/muni/ics/openid/connect/config/ConfigurationPropertiesBean.java
@@ -75,6 +75,15 @@ public class ConfigurationPropertiesBean {
return issuer;
}
+ public String getIssuer(boolean trailingSlash) {
+ String iss = issuer.endsWith("/") ? issuer.substring(0, issuer.length() - 1) : issuer;
+ if (trailingSlash) {
+ return iss + '/';
+ } else {
+ return iss;
+ }
+ }
+
public void setIssuer(String iss) {
issuer = iss;
}