001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.rest.guard; 014 015import java.text.*; 016import java.util.*; 017import java.util.stream.*; 018 019import org.apache.juneau.rest.*; 020 021/** 022 * {@link RestGuard} that uses role expressions to determine whether an authenticated user has access to a class or method. 023 * 024 * <p> 025 * The role expression supports the following constructs: 026 * <ul> 027 * <li><js>"foo"</js> - Single arguments. 028 * <li><js>"foo,bar,baz"</js> - Multiple OR'ed arguments. 029 * <li><js>"foo | bar | bqz"</js> - Multiple OR'ed arguments, pipe syntax. 030 * <li><js>"foo || bar || bqz"</js> - Multiple OR'ed arguments, Java-OR syntax. 031 * <li><js>"fo*"</js> - Patterns including <js>'*'</js> and <js>'?'</js>. 032 * <li><js>"fo* & *oo"</js> - Multiple AND'ed arguments, ampersand syntax. 033 * <li><js>"fo* && *oo"</js> - Multiple AND'ed arguments, Java-AND syntax. 034 * <li><js>"fo* || (*oo || bar)"</js> - Parenthesis. 035 * </ul> 036 * 037 * <h5 class='section'>Notes:</h5><ul> 038 * <li class='note'>AND operations take precedence over OR operations (as expected). 039 * <li class='note'>Whitespace is ignored. 040 * <li class='note'><jk>null</jk> or empty expressions always match as <jk>false</jk>. 041 * </ul> 042 * 043 * <h5 class='section'>See Also:</h5><ul> 044 * <li class='link'><a class="doclink" href="../../../../../index.html#jrs.Guards">Guards</a> 045 * </ul> 046 */ 047public class RoleBasedRestGuard extends RestGuard { 048 049 private final Set<String> roles; 050 private final RoleMatcher roleMatcher; 051 052 /** 053 * Constructor. 054 * 055 * @param declaredRoles 056 * List of possible declared roles. 057 * <br>If <jk>null</jk>, we find the roles in the expression itself. 058 * <br>This is only needed if you're using pattern matching in the expression. 059 * @param roleExpression 060 * The role expression. 061 * <br>If <jk>null</jk> or empty/blanks, the this guard will never pass. 062 * @throws ParseException Invalid role expression syntax. 063 */ 064 public RoleBasedRestGuard(Set<String> declaredRoles, String roleExpression) throws ParseException { 065 roleMatcher = new RoleMatcher(roleExpression); 066 roles = new TreeSet<>(declaredRoles == null ? roleMatcher.getRolesInExpression() : declaredRoles); 067 } 068 069 @Override 070 public boolean isRequestAllowed(RestRequest req) { 071 Set<String> userRoles = roles.stream().filter(x -> req.isUserInRole(x)).collect(Collectors.toSet()); 072 return roleMatcher.matches(userRoles); 073 } 074}