/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates.
*
* 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.uberfire.security.impl.authz;
import org.jboss.errai.common.client.api.annotations.Portable;
import org.uberfire.security.authz.AuthorizationResult;
import org.uberfire.security.authz.Permission;
import static org.uberfire.security.authz.AuthorizationResult.ACCESS_ABSTAIN;
import static org.uberfire.security.authz.AuthorizationResult.ACCESS_DENIED;
import static org.uberfire.security.authz.AuthorizationResult.ACCESS_GRANTED;
/**
* An implementation where the permission's name is formatted using dots. For instance:
* <p>
* <ul>
* <li><b>resource.view</b> => View all resources</li>
* <li><b>resource.view.r1</b> => View only r1</li>
* </ul>
* The {@code implies(Permission other)} implementation is based on the simple fact that one permission implies
* another just if its name starts with the another's name. This very simple mechanism can be applied to most of
* the resources that require authorization control, like for instance, workbench perspectives, a file system, etc.
*/
@Portable
public class DotNamedPermission implements Permission,
Comparable<Permission> {
private String name;
private AuthorizationResult result;
private boolean _immutable;
public DotNamedPermission() {
}
public DotNamedPermission(String name) {
this(name,
ACCESS_ABSTAIN);
}
public DotNamedPermission(String name,
Boolean granted) {
this.name = name;
result = granted == null ? ACCESS_ABSTAIN : (granted ? ACCESS_GRANTED : ACCESS_DENIED);
}
public DotNamedPermission(String name,
AuthorizationResult result) {
this.name = name;
this.result = result;
}
protected void _enableImmutability() {
_immutable = true;
}
protected void _checkImmutability() {
if (_immutable) {
throw new IllegalStateException("The permission is non mutable: " + this);
}
}
public <T extends DotNamedPermission> T nonMutable() {
_enableImmutability();
return (T) this;
}
@Override
public String getName() {
return name;
}
public void setName(String name) {
_checkImmutability();
this.name = name;
}
@Override
public AuthorizationResult getResult() {
return result;
}
public void setResult(AuthorizationResult result) {
_checkImmutability();
this.result = result;
}
@Override
public boolean implies(Permission other) {
return impliesName(other) && impliesResult(other);
}
@Override
public boolean impliesName(Permission other) {
if (equalsName(other)) {
return true;
}
if (name == null) {
return false;
}
String otherName = other.getName();
int lastDot = name.trim().length();
int otherLastDot = otherName != null ? otherName.lastIndexOf('.') : -1;
if (lastDot != otherLastDot) {
return false;
}
return other.getName().substring(0,
lastDot).equals(name);
}
@Override
public boolean impliesResult(Permission other) {
if (result == null || ACCESS_ABSTAIN.equals(result)) {
return other.getResult() == null || ACCESS_ABSTAIN.equals(other.getResult());
}
boolean otherDenied = other.getResult() != null && ACCESS_DENIED.equals(other.getResult());
return ACCESS_DENIED.equals(result) == otherDenied;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (!(obj instanceof Permission)) {
return false;
}
Permission other = (Permission) obj;
return equalsName(other) && equalsResult(other);
}
public boolean equalsName(Permission other) {
if (name != null && !name.equals(other.getName())) {
return false;
}
if (name == null && other.getName() != null) {
return false;
}
return true;
}
public boolean equalsResult(Permission other) {
if (result == null && other.getResult() != null) {
return false;
}
if (result != null && !result.equals(other.getResult())) {
return false;
}
return true;
}
@Override
public int compareTo(Permission o) {
if (name == null) {
return o.getName() == null ? 0 : -1;
}
return name.compareTo(o.getName());
}
@Override
public Permission clone() {
return new DotNamedPermission(name,
result);
}
public String toString() {
StringBuilder out = new StringBuilder();
out.append(name).append(" ").append(result);
return out.toString();
}
}