001/* 002 * Licensed to DuraSpace under one or more contributor license agreements. 003 * See the NOTICE file distributed with this work for additional information 004 * regarding copyright ownership. 005 * 006 * DuraSpace licenses this file to you under the Apache License, 007 * Version 2.0 (the "License"); you may not use this file except in 008 * compliance with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.fcrepo.auth.xacml; 019 020import static org.fcrepo.auth.xacml.URIConstants.ATTRIBUTEID_ACTION_ID; 021import static org.fcrepo.auth.xacml.URIConstants.ATTRIBUTEID_ENVIRONMENT_ORIGINAL_IP_ADDRESS; 022import static org.fcrepo.auth.xacml.URIConstants.ATTRIBUTEID_RESOURCE_ID; 023import static org.fcrepo.auth.xacml.URIConstants.ATTRIBUTEID_RESOURCE_WORKSPACE; 024import static org.fcrepo.auth.xacml.URIConstants.ATTRIBUTEID_SUBJECT_ID; 025import static org.fcrepo.auth.xacml.URIConstants.FCREPO_SUBJECT_GROUP; 026import static org.fcrepo.auth.xacml.URIConstants.FCREPO_SUBJECT_ROLE; 027 028import java.io.ByteArrayOutputStream; 029import java.io.IOException; 030import java.security.Principal; 031import java.util.ArrayList; 032import java.util.List; 033import java.util.Set; 034 035import org.jboss.security.xacml.sunxacml.BasicEvaluationCtx; 036import org.jboss.security.xacml.sunxacml.EvaluationCtx; 037import org.jboss.security.xacml.sunxacml.ParsingException; 038import org.jboss.security.xacml.sunxacml.attr.StringAttribute; 039import org.jboss.security.xacml.sunxacml.ctx.Attribute; 040import org.jboss.security.xacml.sunxacml.ctx.RequestCtx; 041import org.jboss.security.xacml.sunxacml.ctx.Subject; 042import org.jboss.security.xacml.sunxacml.finder.AttributeFinder; 043import org.jboss.security.xacml.sunxacml.finder.AttributeFinderModule; 044import org.slf4j.Logger; 045import org.slf4j.LoggerFactory; 046 047 048/** 049 * @author Gregory Jansen 050 * 051 */ 052public class FedoraEvaluationCtxBuilder { 053 054 /** 055 * Class-level logger. 056 */ 057 private static final Logger LOGGER = LoggerFactory.getLogger(FedoraEvaluationCtxBuilder.class); 058 059 /** 060 * The list of other subjects. 061 */ 062 private final List<Subject> subjectList = new ArrayList<>(); 063 064 /** 065 * This list of resource attributes. 066 */ 067 private final List<Attribute> resourceList = new ArrayList<>(); 068 069 /** 070 * This list of action attributes. 071 */ 072 private final List<Attribute> actionList = new ArrayList<>(); 073 074 /** 075 * This list of environment attributes. 076 */ 077 private final List<Attribute> environmentList = new ArrayList<>(); 078 079 /** 080 * The list of attribute finder modules. 081 */ 082 private final List<AttributeFinderModule> attributeFinderModules = new ArrayList<>(); 083 084 /** 085 * Build the evaluation context. 086 * 087 * @return the evaluation context 088 */ 089 public final EvaluationCtx build() { 090 final RequestCtx rc = new RequestCtx(subjectList, resourceList, actionList, environmentList); 091 if (LOGGER.isDebugEnabled()) { 092 try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { 093 rc.encode(baos); 094 LOGGER.debug("RequestCtx dump:\n{}", baos.toString("utf-8")); 095 } catch (final IOException e) { 096 LOGGER.info("Cannot print request context", e); 097 } 098 } 099 100 final AttributeFinder af = new AttributeFinder(); 101 af.setModules(attributeFinderModules); 102 try { 103 final BasicEvaluationCtx result = new BasicEvaluationCtx(rc, af); 104 // result.setResourceId(resourceId); 105 return result; 106 } catch (final ParsingException e) { 107 throw new Error(e); 108 } 109 } 110 111 /** 112 * Add a finder module to context. 113 * 114 * @param module module to add 115 * @return the builder 116 */ 117 public final FedoraEvaluationCtxBuilder addFinderModule(final AttributeFinderModule module) { 118 this.attributeFinderModules.add(module); 119 return this; 120 } 121 122 /** 123 * Adds a basic Fedora subject to the context. 124 * 125 * @param username the user principal name, or null 126 * @param roles the effective roles for user, or null 127 * @return the builder 128 */ 129 public final FedoraEvaluationCtxBuilder addSubject(final String username, final Set<String> roles) { 130 final List<Attribute> subjectAttrs = new ArrayList<>(); 131 if (username != null) { 132 final StringAttribute v = new StringAttribute(username); 133 final Attribute sid = new Attribute(ATTRIBUTEID_SUBJECT_ID, null, null, v); 134 subjectAttrs.add(sid); 135 } 136 137 if (roles != null) { 138 for (final String role : roles) { 139 final StringAttribute roleAttr = new StringAttribute(role); 140 final Attribute roleId = new Attribute(FCREPO_SUBJECT_ROLE, null, null, roleAttr); 141 subjectAttrs.add(roleId); 142 } 143 } 144 145 this.subjectList.add(new Subject(subjectAttrs)); 146 return this; 147 } 148 149 /** 150 * Add the node or property path as resource ID. 151 * 152 * @param rawModeShapePath the path to the node or property 153 * @return the builder 154 */ 155 public final FedoraEvaluationCtxBuilder addResourceID(final String rawModeShapePath) { 156 final Attribute rid = new Attribute(ATTRIBUTEID_RESOURCE_ID, null, null, new StringAttribute(rawModeShapePath)); 157 resourceList.add(rid); 158 return this; 159 } 160 161 /** 162 * Add the workspace name. 163 * 164 * @param name name of workspace 165 * @return the builder 166 */ 167 public final FedoraEvaluationCtxBuilder addWorkspace(final String name) { 168 final Attribute wid = new Attribute(ATTRIBUTEID_RESOURCE_WORKSPACE, null, null, new StringAttribute(name)); 169 resourceList.add(wid); 170 return this; 171 } 172 173 /** 174 * Adds actions as action ID and modify resource scope to handle remove. 175 * 176 * @param actions the requested actions 177 * @return the builder 178 */ 179 public final FedoraEvaluationCtxBuilder addActions(final String[] actions) { 180 if (actions != null) { 181 for (final String action : actions) { 182 final Attribute a = new Attribute(ATTRIBUTEID_ACTION_ID, null, null, new StringAttribute(action)); 183 actionList.add(a); 184 // if ("remove".equals(action)) { 185 // final Attribute scope = 186 // new Attribute(ATTRIBUTEID_RESOURCE_SCOPE, null, null, 187 // new StringAttribute("Descendants")); 188 // resourceList.add(scope); 189 // } 190 } 191 } 192 return this; 193 } 194 195 /** 196 * @param remoteAddr the remote address 197 */ 198 public void addOriginalRequestIP(final String remoteAddr) { 199 final Attribute a = new Attribute(ATTRIBUTEID_ENVIRONMENT_ORIGINAL_IP_ADDRESS, 200 null, 201 null, 202 new StringAttribute(remoteAddr)); 203 actionList.add(a); 204 } 205 206 /** 207 * This method adds group attributes to the subject-set. 208 * 209 * @param user for arg groups 210 * @param allGroups to be added to the subject-set 211 * @return this object 212 */ 213 public FedoraEvaluationCtxBuilder addGroups(final Principal user, final Set<Principal> allGroups) { 214 LOGGER.trace("For user, {}, adding groups {}", user.getName(), allGroups); 215 216 if (null == user || null == allGroups || allGroups.isEmpty()) { 217 LOGGER.trace("Not adding any groups!"); 218 return this; 219 } 220 221 final List<Attribute> subjectAttrs = new ArrayList<>(); 222 for (final Principal group : allGroups) { 223 // Do not include the user principal in the group attributes. 224 if (!group.equals(user)) { 225 final StringAttribute groupAttr = new StringAttribute(group.getName()); 226 final Attribute groupId = new Attribute(FCREPO_SUBJECT_GROUP, null, null, groupAttr); 227 subjectAttrs.add(groupId); 228 } 229 } 230 this.subjectList.add(new Subject(subjectAttrs)); 231 return this; 232 } 233 234}