/**
*
*/
package com.thinkbiganalytics.security.rest.controller;
/*-
* #%L
* thinkbig-security-controller
* %%
* Copyright (C) 2017 ThinkBig Analytics
* %%
* 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.
* #L%
*/
import com.thinkbiganalytics.security.GroupPrincipal;
import com.thinkbiganalytics.security.UsernamePrincipal;
import com.thinkbiganalytics.security.action.AllowableAction;
import com.thinkbiganalytics.security.action.AllowedActions;
import com.thinkbiganalytics.security.rest.model.Action;
import com.thinkbiganalytics.security.rest.model.ActionGroup;
import com.thinkbiganalytics.security.rest.model.PermissionsChange;
import com.thinkbiganalytics.security.rest.model.Role;
import com.thinkbiganalytics.security.rest.model.RoleMembership;
import com.thinkbiganalytics.security.rest.model.PermissionsChange.ChangeType;
import com.thinkbiganalytics.security.role.SecurityRole;
import java.security.Principal;
import java.security.acl.Group;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Contains transformation functions and methods for converting objects between
* the REST and domain access control models.
*/
public class SecurityModelTransform {
public Function<AllowedActions, PermissionsChange> toPermissionsChange(ChangeType changeType,
String name,
Set<String> users,
Set<String> groups) {
return (allowed) -> {
ActionGroup actionSet = toActionGroup(name).apply(allowed);
PermissionsChange change = new PermissionsChange(changeType, actionSet);
change.setUsers(users);
change.setGroups(groups);
return change;
};
}
public Function<AllowedActions, ActionGroup> toActionGroup(String module) {
return (allowed) -> {
List<Action> list = allowed.getAvailableActions().stream()
.map(toAction())
.collect(Collectors.toList());
ActionGroup actions = new ActionGroup(module);
actions.setActions(list);
return actions;
};
}
public Function<AllowableAction, Action> toActionGroup() {
return (allowable) -> {
Action action = new Action(allowable.getSystemName(), allowable.getTitle(), allowable.getDescription());
action.setActions(allowable.getSubActions().stream()
.map(toAction())
.collect(Collectors.toList()));
return action;
};
}
public Function<AllowableAction, Action> toAction() {
return (allowable) -> {
Action action = new Action(allowable.getSystemName(), allowable.getTitle(), allowable.getDescription());
action.setActions(allowable.getSubActions().stream()
.map(toAction())
.collect(Collectors.toList()));
return action;
};
}
public Function<SecurityRole, Role> toRole() {
return (secRole) -> {
Role role = new Role();
role.setSystemName(secRole.getSystemName());
role.setTitle(secRole.getTitle());
role.setDescription(secRole.getDescription());
role.setAllowedActions(toActionGroup(null).apply(secRole.getAllowedActions()));
return role;
};
}
public Function<List<SecurityRole>, List<Role>> toRoles() {
return (securityRoles) -> securityRoles.stream().map(toRole()).collect(Collectors.toList());
}
public Function<com.thinkbiganalytics.metadata.api.security.RoleMembership, RoleMembership> toRoleMembership() {
return (domain) -> {
RoleMembership membership = new RoleMembership();
membership.setRole(toRole().apply(domain.getRole()));
domain.getMembers().forEach(p -> {
if (p instanceof Group) {
membership.getGroups().add(p.getName());
} else {
membership.getUsers().add(p.getName());
}
});
return membership;
};
}
public void addAction(PermissionsChange change, List<? extends com.thinkbiganalytics.security.action.Action> hierarchy) {
ActionGroup actionSet = change.getActionSet();
for (com.thinkbiganalytics.security.action.Action action : hierarchy) {
addHierarchy(actionSet, action.getHierarchy().iterator());
}
}
public UsernamePrincipal asUserPrincipal(String username) {
return new UsernamePrincipal(username);
}
public UsernamePrincipal[] asUserPrincipals(Set<String> userNames) {
return userNames.stream()
.map(name -> asUserPrincipal(name))
.toArray(UsernamePrincipal[]::new);
}
public GroupPrincipal[] asGroupPrincipals(Set<String> userNames) {
return userNames.stream()
.map(name -> new GroupPrincipal(name))
.toArray(GroupPrincipal[]::new);
}
public Set<Principal> collectPrincipals(PermissionsChange changes) {
Set<Principal> set = new HashSet<>();
Collections.addAll(set, asUserPrincipals(changes.getUsers()));
Collections.addAll(set, asGroupPrincipals(changes.getGroups()));
return set;
}
/**
* Creates a set of domain actions from the REST model actions. The resulting set will
* contain only the leaf actions from the domain action hierarchy.
*/
public Set<com.thinkbiganalytics.security.action.Action> collectActions(PermissionsChange changes) {
Set<com.thinkbiganalytics.security.action.Action> set = new HashSet<>();
for (Action modelAction : changes.getActionSet().getActions()) {
loadActionSet(modelAction,
com.thinkbiganalytics.security.action.Action.create(modelAction.getSystemName(),
modelAction.getTitle(),
modelAction.getDescription()),
set);
}
return set;
}
/**
* Adds a new domain action to the set if the REST model action represents a leaf of the action hierarchy.
* Otherwise, it loads the child actions recursively.
*/
public void loadActionSet(Action modelAction,
com.thinkbiganalytics.security.action.Action action,
Set<com.thinkbiganalytics.security.action.Action> set) {
if (modelAction.getActions().isEmpty()) {
set.add(action);
} else {
for (Action modelChild : modelAction.getActions()) {
loadActionSet(modelChild, action.subAction(modelChild.getSystemName(), modelChild.getTitle(), modelChild.getDescription()), set);
}
}
}
//
// public void addAction(PermissionsChange change, com.thinkbiganalytics.security.action.Action domainAction) {
// ActionGroup actionSet = new ActionGroup("");
// addHierarchy(actionSet, domainAction.getHierarchy().iterator());
// }
private void addHierarchy(ActionGroup actionSet, Iterator<com.thinkbiganalytics.security.action.Action> itr) {
if (itr.hasNext()) {
com.thinkbiganalytics.security.action.Action domainAction = itr.next();
Action subAction = actionSet.getAction(domainAction.getSystemName())
.map(sa -> sa)
.orElseGet(() -> {
Action newAction = new Action(domainAction.getSystemName());
actionSet.addAction(newAction);
return newAction;
});
addHierarchy(subAction, itr);
}
}
private void addHierarchy(Action parentAction, Iterator<com.thinkbiganalytics.security.action.Action> itr) {
if (itr.hasNext()) {
com.thinkbiganalytics.security.action.Action domainAction = itr.next();
Action subAction = parentAction.getAction(domainAction.getSystemName())
.map(sa -> sa)
.orElseGet(() -> {
Action newAction = new Action(domainAction.getSystemName());
parentAction.addAction(newAction);
return newAction;
});
addHierarchy(subAction, itr);
}
}
}