blob: 8a7c714cd21b4ccdd977669f9baad459cfcf9869 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.openaz.xacml.admin.util;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionType;
import org.apache.openaz.xacml.admin.XacmlAdminUI;
import org.apache.openaz.xacml.admin.jpa.Attribute;
import org.apache.openaz.xacml.admin.jpa.Category;
import org.apache.openaz.xacml.admin.jpa.ConstraintType;
import org.apache.openaz.xacml.admin.jpa.ConstraintValue;
import org.apache.openaz.xacml.admin.jpa.Datatype;
import org.apache.openaz.xacml.admin.jpa.Obadvice;
import org.apache.openaz.xacml.api.Advice;
import org.apache.openaz.xacml.api.AttributeValue;
import org.apache.openaz.xacml.api.Identifier;
import org.apache.openaz.xacml.api.Obligation;
import org.apache.openaz.xacml.api.XACML3;
import org.apache.openaz.xacml.util.XACMLObjectCopy;
import org.apache.openaz.xacml.util.XACMLPolicyAggregator;
import org.apache.openaz.xacml.util.XACMLPolicyScanner.CallbackResult;
import com.vaadin.addon.jpacontainer.JPAContainer;
import com.vaadin.addon.jpacontainer.provider.CachingMutableLocalEntityProvider;
import com.vaadin.data.Buffered.SourceException;
import com.vaadin.data.Validator.InvalidValueException;
import com.vaadin.ui.UI;
public class XACMLPolicyImporter extends XACMLPolicyAggregator {
private static Log logger = LogFactory.getLog(XACMLPolicyImporter.class);
public enum OPTION {
/*
* Overwrite any existing ID
*/
OVERWRITE_EXISTING,
/*
* Update an existing ID - only ADDs information
*/
UPDATE_EXISTING,
/*
* Does not change an existing ID
*/
DONOTCHANGE_EXISTING
}
public boolean importAttributes = true;
public boolean ignoreStandardAttributes = true;
public boolean addConstraints = true;
public OPTION attributeOption = OPTION.OVERWRITE_EXISTING;
public boolean importObligations = true;
public OPTION obligationOption = OPTION.OVERWRITE_EXISTING;
public boolean importAdvice = true;
public OPTION adviceOption = OPTION.OVERWRITE_EXISTING;
public XACMLPolicyImporter() {
}
public boolean isImportAttributes() {
return importAttributes;
}
public void setImportAttributes(boolean importAttributes) {
this.importAttributes = importAttributes;
}
public boolean isIgnoreStandardAttributes() {
return ignoreStandardAttributes;
}
public void setIgnoreStandardAttributes(boolean ignoreStandardAttributes) {
this.ignoreStandardAttributes = ignoreStandardAttributes;
}
public boolean isAddConstraints() {
return addConstraints;
}
public void setAddConstraints(boolean addConstraints) {
this.addConstraints = addConstraints;
}
public OPTION getAttributeOption() {
return attributeOption;
}
public void setAttributeOption(OPTION attributeOption) {
this.attributeOption = attributeOption;
}
public boolean isImportObligations() {
return importObligations;
}
public void setImportObligations(boolean importObligations) {
this.importObligations = importObligations;
}
public OPTION getObligationOption() {
return obligationOption;
}
public void setObligationOption(OPTION obligationOption) {
this.obligationOption = obligationOption;
}
public boolean isImportAdvice() {
return importAdvice;
}
public void setImportAdvice(boolean importAdvice) {
this.importAdvice = importAdvice;
}
public OPTION getAdviceOption() {
return adviceOption;
}
public void setAdviceOption(OPTION adviceOption) {
this.adviceOption = adviceOption;
}
@Override
public CallbackResult onObligation(Object parent, ObligationExpressionType expression, Obligation obligation) {
if (importObligations) {
super.onObligation(parent, expression, obligation);
}
return CallbackResult.CONTINUE;
}
@Override
public CallbackResult onAttribute(Object parent, Object container, org.apache.openaz.xacml.api.Attribute attribute) {
if (importAttributes) {
super.onAttribute(parent, container, attribute);
}
return CallbackResult.CONTINUE;
}
@Override
public CallbackResult onAdvice(Object parent, AdviceExpressionType expression, Advice advice) {
if (importAdvice) {
super.onAdvice(parent, expression, advice);
}
return CallbackResult.CONTINUE;
}
@Override
public void onFinishScan(Object root) {
if (this.importAttributes && this.doImportAttributes() > 0) {
((XacmlAdminUI)UI.getCurrent()).refreshAttributes();
}
int changes = 0;
if (this.importObligations) {
changes += this.doImportObligations();
}
if (this.importAdvice) {
changes += this.doImportAdvice();
}
//
// If changes were made, we need to tell the UI so the
// dictionary can refresh.
//
if (changes > 0) {
((XacmlAdminUI)UI.getCurrent()).refreshObadvice();
}
}
@SuppressWarnings("unchecked")
protected int doImportAttributes() {
int changes = 0;
//
// Get our attributes. This container is modifiable.
//
JPAContainer<Attribute> attributes = ((XacmlAdminUI)UI.getCurrent()).getAttributes();
//
// Get mutable entity providers for these.
//
JPAContainer<Category> categories = new JPAContainer<Category>(Category.class);
categories.setEntityProvider(new CachingMutableLocalEntityProvider<Category>(Category.class, ((XacmlAdminUI)UI.getCurrent()).getEntityManager()));
JPAContainer<Datatype> datatypes = new JPAContainer<Datatype>(Datatype.class);
datatypes.setEntityProvider(new CachingMutableLocalEntityProvider<Datatype>(Datatype.class, ((XacmlAdminUI)UI.getCurrent()).getEntityManager()));
//
// Work the map
//
for (Identifier cat : this.attributeMap.keySet()) {
//
// Does category exist?
//
Category category = JPAUtils.findCategory(cat);
if (category == null) {
//
// This should rarely happen, but is possible since XACML 3.0
// you can define your own categories.
//
logger.warn("New category: " + cat);
category = new Category(cat, Category.CUSTOM);
String shortName = XACMLConstants.extractShortName(cat.stringValue());
if (shortName != null) {
category.setShortName(shortName);
} else {
category.setShortName(category.getXacmlId());
}
//
// Make sure the grouping is ok
//
if (category.getGrouping() == null) {
category.setGrouping(category.getShortName());
}
//
// Add it in
//
categories.addEntity(category);
//
// Tell the RO to update itself.
//
((XacmlAdminUI)UI.getCurrent()).getCategories().refresh();
}
Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>> map = this.attributeMap.get(cat);
for (Identifier dt : map.keySet()) {
//
// Does datatype exist?
//
Datatype datatype = JPAUtils.findDatatype(dt);
if (datatype == null) {
//
// This should rarely happen, but is possible since XACML 3.0
// you can define new datatypes.
//
logger.warn("New datatype: " + dt);
datatype = new Datatype(dt, Datatype.CUSTOM);
String shortName = XACMLConstants.extractShortName(dt.stringValue());
if (shortName != null) {
datatype.setShortName(shortName);
} else {
datatype.setShortName(datatype.getXacmlId());
}
//
// Add it in
//
datatypes.addEntity(datatype);
//
// Tell the Read-Only property to update itself.
//
((XacmlAdminUI)UI.getCurrent()).getDatatypes().refresh();
}
//
// Iterate the attributes
//
for (Identifier id : map.get(dt).keySet()) {
//
// Do we ignore it if its standard?
//
if (! this.ignoreStandardAttributes ||
XACMLConstants.STANDARD_ATTRIBUTES.contains(id) == false) {
//
// Does it already exist?
//
Attribute newAttribute = null;
Attribute currentAttribute = JPAUtils.findAttribute(category, datatype, id.stringValue());
//
// Support for an existing attribute
//
if (currentAttribute != null) {
if (this.attributeOption == OPTION.OVERWRITE_EXISTING) {
newAttribute = currentAttribute;
newAttribute.setConstraintType(null);
newAttribute.removeAllConstraintValues();
} else if (this.attributeOption == OPTION.DONOTCHANGE_EXISTING) {
logger.info("Do not change existing: " + currentAttribute);
continue;
} else if (this.attributeOption == OPTION.UPDATE_EXISTING) {
newAttribute = currentAttribute;
}
} else {
//
// Create our new attribute
//
newAttribute = new Attribute(id.stringValue(), ((XacmlAdminUI)UI.getCurrent()).getUserid());
newAttribute.setCategoryBean(category);
newAttribute.setDatatypeBean(datatype);
}
//
// Get all the values
//
Set<AttributeValue<?>> values = map.get(dt).get(id);
//
// Do we have more than 1? Also, omit boolean datatype which
// doesn't make any sense to enumerate.
//
if (values.size() > 1 && dt.equals(XACML3.ID_DATATYPE_BOOLEAN) == false) {
//
// We have a lot of possible values, add as an enumeration
//
newAttribute.setConstraintType(JPAUtils.findConstraintType(ConstraintType.ENUMERATION_TYPE));
for (AttributeValue<?> value : values) {
Object val = value.getValue();
String content;
if (val instanceof Collection) {
content = XACMLObjectCopy.getContent((List<Object>) value.getValue());
} else {
content = val.toString();
}
//
// Check if we should add it in
//
boolean add = true;
//
// If we are updating an existing, we can really only do this for enumerations,
// its impossible to resolve a regular expression or range.
//
if (currentAttribute != null && this.attributeOption == OPTION.UPDATE_EXISTING &&
newAttribute.getConstraintType().getConstraintType().equals(ConstraintType.ENUMERATION_TYPE)) {
//
// Make sure it isn't there already, no duplicates.
//
for (ConstraintValue currentConstraintValue : newAttribute.getConstraintValues()) {
if (currentConstraintValue.getValue().equals(content)) {
add = false;
break;
}
}
}
if (add && content.isEmpty() == false) {
ConstraintValue newValue = new ConstraintValue("Enumeration", content);
newValue.setAttribute(newAttribute);
newAttribute.addConstraintValue(newValue);
}
}
}
//
// Add it
//
if (newAttribute != null) {
if (newAttribute.getId() == 0) {
logger.info("Adding new attribute");
if (attributes.addEntity(newAttribute) == null) {
logger.error("Failed to add new attribute: " + newAttribute);
} else {
changes++;
}
} else {
logger.info("Updating attribute " + newAttribute);
try {
attributes.commit();
changes++;
} catch (SourceException | InvalidValueException e) {
logger.error("Update failed: " + e.getLocalizedMessage());
}
}
}
}
}
}
}
return changes;
}
protected int doImportObligations() {
int changes = 0;
JPAContainer<Obadvice> oa = ((XacmlAdminUI)UI.getCurrent()).getObadvice();
for (Identifier id : this.obligationMap.keySet()) {
for (EffectType effect : this.obligationMap.get(id).keySet()) {
for (Obligation obligation : this.obligationMap.get(id).get(effect)) {
Obadvice newObligation = null;
Obadvice currentObligation = JPAUtils.findObligation(obligation.getId(), effect);
//
// Does it exist?
//
if (currentObligation != null) {
if (this.obligationOption == OPTION.OVERWRITE_EXISTING) {
newObligation = currentObligation;
newObligation.removeAllExpressions();
} else if (this.obligationOption == OPTION.DONOTCHANGE_EXISTING) {
continue;
} else if (this.obligationOption == OPTION.UPDATE_EXISTING) {
newObligation = currentObligation;
}
} else {
//
// Create new one
//
newObligation = new Obadvice(obligation.getId(), ((XacmlAdminUI)UI.getCurrent()).getUserid());
newObligation.setFulfillOn((effect == EffectType.PERMIT ? Obadvice.EFFECT_PERMIT : Obadvice.EFFECT_DENY));
}
//
// TODO add the expressions
//
//
// Add it in
//
if (newObligation != null) {
if (newObligation.getId() == 0) {
logger.info("Adding obligation " + newObligation);
oa.addEntity(newObligation);
changes++;
} else {
logger.info("Updating obligation " + newObligation);
try {
oa.commit();
changes++;
} catch (SourceException | InvalidValueException e) {
logger.error("Update obligation failed " + e.getLocalizedMessage());
}
}
}
}
}
}
return changes;
}
protected int doImportAdvice() {
int changes = 0;
JPAContainer<Obadvice> oa = ((XacmlAdminUI)UI.getCurrent()).getObadvice();
for (Identifier id : this.adviceMap.keySet()) {
for (EffectType effect : this.adviceMap.get(id).keySet()) {
for (Advice advice : this.adviceMap.get(id).get(effect)) {
Obadvice newAdvice = null;
Obadvice currentAdvice = JPAUtils.findAdvice(advice.getId(), effect);
//
// Does it exist?
//
if (currentAdvice != null) {
if (this.adviceOption == OPTION.OVERWRITE_EXISTING) {
newAdvice = currentAdvice;
newAdvice.removeAllExpressions();
} else if (this.adviceOption == OPTION.DONOTCHANGE_EXISTING) {
continue;
} else if (this.adviceOption == OPTION.UPDATE_EXISTING) {
newAdvice = currentAdvice;
}
} else {
//
// Create new one
//
newAdvice = new Obadvice(advice.getId(), ((XacmlAdminUI)UI.getCurrent()).getUserid());
newAdvice.setType(Obadvice.ADVICE);
newAdvice.setFulfillOn((effect == EffectType.PERMIT ? Obadvice.EFFECT_PERMIT : Obadvice.EFFECT_DENY));
}
//
// TODO add the expressions
//
//
// Add it in
//
if (newAdvice != null) {
if (newAdvice.getId() == 0) {
logger.info("Adding advice " + newAdvice);
oa.addEntity(newAdvice);
changes++;
} else {
logger.info("Updating advice " + newAdvice);
try {
oa.commit();
changes++;
} catch (SourceException | InvalidValueException e) {
logger.error("Update advice failed " + e.getLocalizedMessage());
}
}
}
}
}
}
return changes;
}
}