From 7951ff508630e7026859f0a434f8adbd9fb2f476 Mon Sep 17 00:00:00 2001 From: Justin Richer Date: Mon, 11 May 2015 14:44:21 -0400 Subject: [PATCH] separated claims processing out into its own service, closes #796 --- .../uma/service/ClaimsProcessingService.java | 45 +++++++++++++ .../uma/service/MatchAllClaimsProcessor.java | 65 +++++++++++++++++++ .../uma/web/AuthorizationRequestEndpoint.java | 42 ++++-------- 3 files changed, 124 insertions(+), 28 deletions(-) create mode 100644 openid-connect-common/src/main/java/org/mitre/uma/service/ClaimsProcessingService.java create mode 100644 openid-connect-server/src/main/java/org/mitre/uma/service/MatchAllClaimsProcessor.java diff --git a/openid-connect-common/src/main/java/org/mitre/uma/service/ClaimsProcessingService.java b/openid-connect-common/src/main/java/org/mitre/uma/service/ClaimsProcessingService.java new file mode 100644 index 000000000..18c531fab --- /dev/null +++ b/openid-connect-common/src/main/java/org/mitre/uma/service/ClaimsProcessingService.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright 2015 The MITRE Corporation + * and the MIT Kerberos and Internet Trust Consortium + * + * 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. + *******************************************************************************/ + +package org.mitre.uma.service; + +import java.util.Collection; + +import org.mitre.uma.model.Claim; + +/** + * + * Processes claims presented during an UMA transaction. + * + * @author jricher + * + */ +public interface ClaimsProcessingService { + + /** + * + * Determine whether or not the claims that have been supplied are + * sufficient to fulfill the requirements given by the claims that + * are required. + * + * @param claimsRequired the required claims to check against + * @param claimsSupplied the supplied claims to test + * @return the unmatched claims (if any), an empty set if the claims are satisfied, never null + */ + public Collection claimsAreSatisfied(Collection claimsRequired, Collection claimsSupplied); + +} diff --git a/openid-connect-server/src/main/java/org/mitre/uma/service/MatchAllClaimsProcessor.java b/openid-connect-server/src/main/java/org/mitre/uma/service/MatchAllClaimsProcessor.java new file mode 100644 index 000000000..f68650365 --- /dev/null +++ b/openid-connect-server/src/main/java/org/mitre/uma/service/MatchAllClaimsProcessor.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright 2015 The MITRE Corporation + * and the MIT Kerberos and Internet Trust Consortium + * + * 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. + *******************************************************************************/ + +package org.mitre.uma.service; + +import java.util.Collection; +import java.util.HashSet; + +import org.mitre.uma.model.Claim; +import org.springframework.stereotype.Service; + +/** + * Tests if all the claims in the required set have a matching + * value in the supplied set. + * + * @author jricher + * + */ +@Service("matchAllClaimsProcessor") +public class MatchAllClaimsProcessor implements ClaimsProcessingService { + + @Override + public Collection claimsAreSatisfied(Collection claimsRequired, Collection claimsSupplied) { + + Collection claimsUnmatched = new HashSet<>(claimsRequired); + + // see if each of the required claims has a counterpart in the supplied claims set + for (Claim required : claimsRequired) { + for (Claim supplied : claimsSupplied) { + + if (required.getIssuer().containsAll(supplied.getIssuer())) { + // it's from the right issuer + + if (required.getName().equals(supplied.getName()) && + required.getValue().equals(supplied.getValue())) { + + // the claim matched, pull it from the set + claimsUnmatched.remove(required); + + } + + } + } + } + + // if there's anything left then the claims aren't satisfied, return the leftovers + return claimsUnmatched; + + } + +} diff --git a/openid-connect-server/src/main/java/org/mitre/uma/web/AuthorizationRequestEndpoint.java b/openid-connect-server/src/main/java/org/mitre/uma/web/AuthorizationRequestEndpoint.java index fc59c1136..bc951f0d8 100644 --- a/openid-connect-server/src/main/java/org/mitre/uma/web/AuthorizationRequestEndpoint.java +++ b/openid-connect-server/src/main/java/org/mitre/uma/web/AuthorizationRequestEndpoint.java @@ -18,6 +18,7 @@ package org.mitre.uma.web; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.UUID; @@ -40,6 +41,7 @@ import org.mitre.openid.connect.view.JsonErrorView; import org.mitre.uma.model.Claim; import org.mitre.uma.model.PermissionTicket; import org.mitre.uma.model.ResourceSet; +import org.mitre.uma.service.ClaimsProcessingService; import org.mitre.uma.service.PermissionService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -105,6 +107,9 @@ public class AuthorizationRequestEndpoint { @Autowired private WebResponseExceptionTranslator providerExceptionHandler; + @Autowired + private ClaimsProcessingService claimsProcessingService; + @RequestMapping(method = RequestMethod.POST, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) public String authorizationRequest(@RequestBody String jsonString, Model m, Authentication auth) { @@ -132,37 +137,18 @@ public class AuthorizationRequestEndpoint { // found the ticket, see if it's any good ResourceSet rs = ticket.getPermission().getResourceSet(); - Collection claimsRequired = rs.getClaimsRequired(); - - Collection claimsSupplied = ticket.getClaimsSupplied(); - Collection claimsUnmatched = new HashSet<>(claimsRequired); - - // see if each of the required claims has a counterpart in the supplied claims set - // TODO: move this component to a claims checking service (#796) - for (Claim required : claimsRequired) { - for (Claim supplied : claimsSupplied) { - - if (required.getIssuer().containsAll(supplied.getIssuer())) { - // it's from the right issuer - - if (required.getName().equals(supplied.getName()) && - required.getValue().equals(supplied.getValue())) { - - // the claim matched, pull it from the set - claimsUnmatched.remove(required); - - } - - - } - } + if (rs.getClaimsRequired() == null || rs.getClaimsRequired().isEmpty()) { + // the required claims are empty, this resource has no way to be authorized + + m.addAttribute(JsonErrorView.ERROR, "not_authorized"); + m.addAttribute(JsonErrorView.ERROR_MESSAGE, "This resource set can not be accessed."); + m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); } + + Collection claimsUnmatched = claimsProcessingService.claimsAreSatisfied(rs.getClaimsRequired(), ticket.getClaimsSupplied()); - // note that if the required claims are empty we don't want to return a token - if (!claimsRequired.isEmpty() && claimsUnmatched.isEmpty()) { - // we matched all the claims, create and return the token - + if (claimsUnmatched.isEmpty()) { // TODO: move this whole mess to the OIDCTokenService (#797)