Skip to content

Commit

Permalink
Support for exceptItem in authorizations. Authorization refactoring/s…
Browse files Browse the repository at this point in the history
…implification.
  • Loading branch information
semancik committed Jan 26, 2018
1 parent e77c314 commit 75206c1
Show file tree
Hide file tree
Showing 30 changed files with 1,105 additions and 526 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2017 Evolveum
* Copyright (c) 2010-2018 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -35,7 +35,7 @@
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.security.api.ItemSecurityDecisions;
import com.evolveum.midpoint.security.enforcer.api.ItemSecurityConstraints;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.exception.CommunicationException;
import com.evolveum.midpoint.util.exception.ConfigurationException;
Expand Down Expand Up @@ -138,7 +138,7 @@ public class AssignmentEditorPanel extends BasePanel<AssignmentEditorDto> {
protected WebMarkupContainer headerRow;
protected IModel<List<AssignmentInfoDto>> privilegesListModel;
protected boolean delegatedToMe;
private LoadableModel<ItemSecurityDecisions> decisionsModel;
private LoadableModel<ItemSecurityConstraints> itemSecurityConstraintsModel;

public AssignmentEditorPanel(String id, IModel<AssignmentEditorDto> model, boolean delegatedToMe,
LoadableModel<List<AssignmentInfoDto>> privilegesListModel) {
Expand Down Expand Up @@ -1106,34 +1106,26 @@ protected boolean ignoreMandatoryAttributes(){
return false;
}

private void initDecisionsModel(){
decisionsModel = new LoadableModel<ItemSecurityDecisions>(false) {
private void initDecisionsModel() {
itemSecurityConstraintsModel = new LoadableModel<ItemSecurityConstraints>(false) {
@Override
protected ItemSecurityDecisions load() {
return loadSecurityDecisions();
protected ItemSecurityConstraints load() {
return loadSecurityConstraints();
}
};

}

private boolean isItemAllowed(ItemPath itemPath){
ItemSecurityDecisions decisions = decisionsModel.getObject();
if (itemPath == null || decisions == null || decisions.getItemDecisionMap() == null
|| decisions.getItemDecisionMap().size() == 0){
private boolean isItemAllowed(ItemPath itemPath) {
ItemSecurityConstraints constraints = itemSecurityConstraintsModel.getObject();
if (itemPath == null || constraints == null) {
return true;
}
Map<ItemPath, AuthorizationDecisionType> decisionsMap = decisions.getItemDecisionMap();
boolean isAllowed = false;
for (ItemPath path : decisionsMap.keySet()) {
if (path.equivalent(itemPath)
&& AuthorizationDecisionType.ALLOW.value().equals(decisionsMap.get(path).value())) {
return true;
}
}
return isAllowed;
AuthorizationDecisionType decision = constraints.findItemDecision(itemPath);
return AuthorizationDecisionType.ALLOW.equals(decision);
}

private ItemSecurityDecisions loadSecurityDecisions(){
private ItemSecurityConstraints loadSecurityConstraints() {
PageBase pageBase = getPageBase();
if (pageBase == null || getModelObject().getTargetRef() == null){
return null;
Expand All @@ -1159,15 +1151,15 @@ private ItemSecurityDecisions loadSecurityDecisions(){
OperationResult result = new OperationResult(OPERATION_LOAD_TARGET_OBJECT);
PrismObject<AbstractRoleType> targetRefObject = WebModelServiceUtils.loadObject(AbstractRoleType.class,
targetObjectOid, pageBase, task, result);
ItemSecurityDecisions decisions = null;
ItemSecurityConstraints constraints = null;
try{
decisions =
constraints =
pageBase.getModelInteractionService().getAllowedRequestAssignmentItems(operationObject, targetRefObject, task, result);

} catch (SchemaException | SecurityViolationException | ObjectNotFoundException | ExpressionEvaluationException | CommunicationException | ConfigurationException ex){
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load security decisions for assignment items.", ex);
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load security constraints for assignment items.", ex);
}
return decisions;
return constraints;
}

}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2017 Evolveum
* Copyright (c) 2010-2018 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -24,6 +24,7 @@
import com.evolveum.midpoint.security.api.*;
import com.evolveum.midpoint.security.enforcer.api.AccessDecision;
import com.evolveum.midpoint.security.enforcer.api.AuthorizationParameters;
import com.evolveum.midpoint.security.enforcer.api.ItemSecurityConstraints;
import com.evolveum.midpoint.security.enforcer.api.ObjectSecurityConstraints;
import com.evolveum.midpoint.security.enforcer.api.SecurityEnforcer;
import com.evolveum.midpoint.task.api.Task;
Expand Down Expand Up @@ -323,7 +324,7 @@ public <T> T runPrivileged(Producer<T> producer) {
}

@Override
public <O extends ObjectType, R extends AbstractRoleType> ItemSecurityDecisions getAllowedRequestAssignmentItems(
public <O extends ObjectType, R extends AbstractRoleType> ItemSecurityConstraints getAllowedRequestAssignmentItems(
MidPointPrincipal midPointPrincipal, String actionUri, PrismObject<O> object, PrismObject<R> target,
OwnerResolver ownerResolver, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException {
return securityEnforcer.getAllowedRequestAssignmentItems(midPointPrincipal, actionUri, object, target, ownerResolver, task, result);
Expand Down
Expand Up @@ -200,6 +200,8 @@ public abstract class SchemaConstants {
*/
public static final QName ORG_CONSENT = new QName(NS_ORG, "consent");

public static final ItemPath PATH_NAME = new ItemPath(ObjectType.F_NAME);
public static final ItemPath PATH_DESCRIPTION = new ItemPath(ObjectType.F_DESCRIPTION);
public static final ItemPath PATH_PASSWORD = new ItemPath(C_CREDENTIALS, CredentialsType.F_PASSWORD);
public static final ItemPath PATH_PASSWORD_VALUE = new ItemPath(C_CREDENTIALS, CredentialsType.F_PASSWORD,
PasswordType.F_VALUE);
Expand Down Expand Up @@ -231,6 +233,10 @@ public abstract class SchemaConstants {
public static final ItemPath PATH_ASSIGNMENT = new ItemPath(FocusType.F_ASSIGNMENT);
public static final ItemPath PATH_ASSIGNMENT_ACTIVATION = new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_ACTIVATION);
public static final ItemPath PATH_ASSIGNMENT_ACTIVATION_EFFECTIVE_STATUS = new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_ACTIVATION, ActivationType.F_EFFECTIVE_STATUS);
public static final ItemPath PATH_ASSIGNMENT_ACTIVATION_VALID_FROM = new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_ACTIVATION, ActivationType.F_VALID_FROM);
public static final ItemPath PATH_ASSIGNMENT_ACTIVATION_VALID_TO = new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_ACTIVATION, ActivationType.F_VALID_TO);
public static final ItemPath PATH_ASSIGNMENT_TARGET_REF = new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_TARGET_REF);
public static final ItemPath PATH_ASSIGNMENT_DESCRIPTION = new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_DESCRIPTION);
public static final ItemPath PATH_ASSOCIATION = new ItemPath(C_ASSOCIATION);
public static final ItemPath PATH_TRIGGER = new ItemPath(ObjectType.F_TRIGGER);
public static final ItemPath PATH_CREDENTIALS_PASSWORD_FAILED_LOGINS = new ItemPath(
Expand Down
Expand Up @@ -10279,7 +10279,29 @@
<xsd:sequence>
<xsd:element name="name" type="xsd:string" minOccurs="0"/>
<xsd:element ref="tns:description" minOccurs="0"/>
<xsd:element name="decision" minOccurs="0" type="tns:AuthorizationDecisionType" default="allow"/>
<xsd:element name="decision" minOccurs="0" type="tns:AuthorizationDecisionType" default="allow">
<xsd:annotation>
<xsd:documentation>
<p>
Decision that this authorization specifies. If the decision is "allow" (which is the
default) then this authorization allows access. If the decision is "deny" then this
authorization denies access. Denial is a final decisions. If at least one applicable
authorization denies access then the access is always denied, regadless of any other
allow authorizations.
</p>
<p>
Note: there is subtle (but important) difference between not allowing access and
denying access. Authorization that denies access specifies a final decision. Denied
access cannot be allowed by any other authorization. Deny authorization are very
strong from a security perspective, but it is extremely difficult to combine them
with other authorizations. Therefore deny authorizations are used very rarely.
On the other hand if the access is not allowed by a specific authorization then
it can still be allowed by another authorization. This makes authorizations "mergeable".
Not allowing access is usually the right approach.
</p>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="action" type="xsd:anyURI" minOccurs="1" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
Expand Down Expand Up @@ -10317,12 +10339,50 @@
<xsd:element name="item" type="t:ItemPathType" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
Specification of items that form a scope of this authorization. This autorization will
only affect the items specified in this element. If no items are specified then the
authorization applies to all items in the objects.
<p>
Specification of items that form a scope of this authorization. This autorization will
only affect the items specified in this element. If no items are specified then the
authorization applies to all items in the objects.
</p>
<p>
The item specification must not be combined with exceptItem. One or the other can be
used, but not both. If neither item nor exceptItem is specified then it is assumed
that the authorization applies to all items.
</p>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="exceptItem" type="t:ItemPathType" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
<p>
Specification of items that are excluded from the scope of this authorization.
I.e. the authorization applies to all the items except those items that are
specified here.
</p>
<p>
Note: there is subtle (but important) difference between not allowing access and
denying access. Authorization that denies access specifies a final decision. Denied
access cannot be allowed by any other authorization. Deny authorization are very
strong from a security perspective, but it is extremely difficult to combine them
with other authorizations. Therefore deny authorizations are used very rarely.
On the other hand if the access is not allowed by a specific authorization then
it can still be allowed by another authorization. This makes authorizations "mergeable".
Not allowing access is usually the right approach.
The exceptItem specification is a convenient way to "not allow" access to specific
items.
</p>
<p>
The item specification must not be combined with exceptItem. One or the other can be
used, but not both. If neither item nor exceptItem is specified then it is assumed
that the authorization applies to all items.
</p>
</xsd:documentation>
<xsd:appinfo>
<a:since>3.7.1</a:since>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
<xsd:element name="target" type="tns:OwnedObjectSelectorType" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
Expand Down
Expand Up @@ -210,7 +210,7 @@ public static void debugDumpWithLabelLn(StringBuilder sb, String label, DebugDum
debugDumpWithLabel(sb,label,dd,indent);
sb.append("\n");
}

public static void debugDumpWithLabel(StringBuilder sb, String label, DebugDumpable dd, int indent) {
debugDumpLabel(sb, label, indent);
if (dd == null) {
Expand All @@ -221,6 +221,21 @@ public static void debugDumpWithLabel(StringBuilder sb, String label, DebugDumpa
}
}

public static void debugDumpShortWithLabelLn(StringBuilder sb, String label, ShortDumpable sd, int indent) {
debugDumpShortWithLabel(sb, label, sd, indent);
sb.append("\n");
}

public static void debugDumpShortWithLabel(StringBuilder sb, String label, ShortDumpable sd, int indent) {
debugDumpLabel(sb, label, indent);
if (sd == null) {
sb.append(" null");
} else {
sb.append(" ");
sd.shortDump(sb);
}
}

public static void debugDumpWithLabel(StringBuilder sb, String label, String val, int indent) {
debugDumpLabel(sb, label, indent);
sb.append(" ");
Expand Down
7 changes: 6 additions & 1 deletion model/model-api/pom.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
~ Copyright (c) 2010-2017 Evolveum
~ Copyright (c) 2010-2018 Evolveum
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -77,6 +77,11 @@
<artifactId>security-api</artifactId>
<version>3.7-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.evolveum.midpoint.repo</groupId>
<artifactId>security-enforcer-api</artifactId>
<version>3.7-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.evolveum.midpoint.repo</groupId>
<artifactId>audit-api</artifactId>
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2017 Evolveum
* Copyright (c) 2010-2018 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -28,8 +28,8 @@
import com.evolveum.midpoint.schema.ResourceShadowDiscriminator;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.statistics.ConnectorOperationalStatus;
import com.evolveum.midpoint.security.api.ItemSecurityDecisions;
import com.evolveum.midpoint.security.api.MidPointPrincipal;
import com.evolveum.midpoint.security.enforcer.api.ItemSecurityConstraints;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.DisplayableValue;
import com.evolveum.midpoint.util.exception.*;
Expand Down Expand Up @@ -182,7 +182,7 @@ <F extends ObjectType> ModelContext<F> previewChanges(
* @param object object of the operation (user)
* @param target target of the operation (role, org, service that is being assigned)
*/
<O extends ObjectType,R extends AbstractRoleType> ItemSecurityDecisions getAllowedRequestAssignmentItems(PrismObject<O> object, PrismObject<R> target, Task task, OperationResult result) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException;
<O extends ObjectType,R extends AbstractRoleType> ItemSecurityConstraints getAllowedRequestAssignmentItems(PrismObject<O> object, PrismObject<R> target, Task task, OperationResult result) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException;

SecurityPolicyType getSecurityPolicy(PrismObject<UserType> user, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException;

Expand Down
Expand Up @@ -53,7 +53,10 @@
import com.evolveum.midpoint.schema.*;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.security.api.*;
import com.evolveum.midpoint.security.api.MidPointPrincipal;
import com.evolveum.midpoint.security.api.SecurityContextManager;
import com.evolveum.midpoint.security.api.UserProfileService;
import com.evolveum.midpoint.security.enforcer.api.ItemSecurityConstraints;
import com.evolveum.midpoint.security.enforcer.api.ObjectSecurityConstraints;
import com.evolveum.midpoint.security.enforcer.api.SecurityEnforcer;
import com.evolveum.midpoint.util.DOMUtil;
Expand Down Expand Up @@ -378,7 +381,7 @@ public RefinedObjectClassDefinition getEditObjectClassDefinition(PrismObject<Sha
return layeredROCD;
}

public <O extends ObjectType,R extends AbstractRoleType> ItemSecurityDecisions getAllowedRequestAssignmentItems(PrismObject<O> object, PrismObject<R> target, Task task, OperationResult result) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException {
public <O extends ObjectType,R extends AbstractRoleType> ItemSecurityConstraints getAllowedRequestAssignmentItems(PrismObject<O> object, PrismObject<R> target, Task task, OperationResult result) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException {
return securityEnforcer.getAllowedRequestAssignmentItems(securityContextManager.getPrincipal(), ModelAuthorizationAction.ASSIGN.getUrl(), object, target, null, task, result);
}

Expand Down
Expand Up @@ -357,13 +357,9 @@ public <D extends ItemDefinition> void applySecurityConstraints(D itemDefinition
private <D extends ItemDefinition> void applySecurityConstraintsPhase(D itemDefinition, ObjectSecurityConstraints securityConstraints,
AuthorizationPhaseType phase) {
Validate.notNull(phase);
AuthorizationDecisionType defaultReadDecision = securityConstraints.getActionDecision(ModelAuthorizationAction.READ.getUrl(), phase);
AuthorizationDecisionType defaultAddDecision = securityConstraints.getActionDecision(ModelAuthorizationAction.ADD.getUrl(), phase);
AuthorizationDecisionType defaultModifyDecision = securityConstraints.getActionDecision(ModelAuthorizationAction.MODIFY.getUrl(), phase);
LOGGER.trace("applySecurityConstraints(itemDefs): def={}, phase={}, defaults R={}, A={}, M={}",
itemDefinition, phase, defaultReadDecision, defaultAddDecision, defaultModifyDecision);
LOGGER.trace("applySecurityConstraints(itemDefs): def={}, phase={}", itemDefinition, phase);
applySecurityConstraintsItemDef(itemDefinition, new IdentityHashMap<>(), ItemPath.EMPTY_PATH, securityConstraints,
defaultReadDecision, defaultAddDecision, defaultModifyDecision, phase);
null, null, null, phase);

}

Expand Down Expand Up @@ -435,7 +431,7 @@ private <D extends ItemDefinition> void applySecurityConstraintsItemDef(D itemDe
public AuthorizationDecisionType computeItemDecision(ObjectSecurityConstraints securityConstraints, ItemPath nameOnlyItemPath, String actionUrl,
AuthorizationDecisionType defaultDecision, AuthorizationPhaseType phase) {
AuthorizationDecisionType explicitDecision = securityConstraints.findItemDecision(nameOnlyItemPath, actionUrl, phase);
// LOGGER.trace("Explicit decision for {}: {}", itemPath, explicitDecision);
// LOGGER.trace("Explicit decision for {} ({} {}): {}", nameOnlyItemPath, actionUrl, phase, explicitDecision);
if (explicitDecision != null) {
return explicitDecision;
} else {
Expand Down

0 comments on commit 75206c1

Please sign in to comment.