Skip to content

Commit

Permalink
[SHIBUI-906]
Browse files Browse the repository at this point in the history
WIP. Won't compile yet.

Converted ModelRepresentationConversions
.getAttributeListFromRelyingPartyOverridesRepresentation to build
attributes using generic displayTypes. Added support for set and integer
displayTypes to AttributeUtility.

Added attributeName and attributeFriendlyName to
RelyingPartyOverrideProperty.

Removed println.
  • Loading branch information
Bill Smith committed Oct 10, 2018
1 parent 8b0a1ed commit 1837ae1
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ public class ConfigurationController {

@GetMapping(value = "/customAttributes")
public ResponseEntity<?> getCustomAttributes() {
System.out.println("WOO!\n" + customPropertiesConfiguration.getOverrides());
return ResponseEntity.ok(customPropertiesConfiguration.getAttributes());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public class RelyingPartyOverrideProperty {
private String persistValue;
private List<String> defaultValues;
private Collection<String> persistValues;
private String attributeName;
private String attributeFriendlyName;

public String getName() {
return name;
Expand Down Expand Up @@ -80,8 +82,35 @@ public void setPersistValues(Collection<String> persistValues) {
this.persistValues = persistValues;
}

public String getAttributeName() {
return attributeName;
}

public void setAttributeName(String attributeName) {
this.attributeName = attributeName;
}

public String getAttributeFriendlyName() {
return attributeFriendlyName;
}

public void setAttributeFriendlyName(String attributeFriendlyName) {
this.attributeFriendlyName = attributeFriendlyName;
}

@Override
public String toString() {
return "RelyingPartyOverrideProperty{" + "\nname='" + name + '\'' + ", \ndisplayName='" + displayName + '\'' + ", \ndisplayType='" + displayType + '\'' + ", \nhelpText='" + helpText + '\'' + ", \npersistType='" + persistType + '\'' + ", \npersistValue='" + persistValue + '\'' + ", \ndefaultValues=" + defaultValues + ", \npersistValues=" + persistValues + "\n}";
return "RelyingPartyOverrideProperty{"
+ "\nname='" + name + '\''
+ ", \ndisplayName='" + displayName + '\''
+ ", \ndisplayType='" + displayType + '\''
+ ", \nhelpText='" + helpText + '\''
+ ", \npersistType='" + persistType + '\''
+ ", \npersistValue='" + persistValue + '\''
+ ", \ndefaultValues=" + defaultValues
+ ", \npersistValues=" + persistValues
+ ", \nattributeName='" + attributeName + '\''
+ ", \nattributeFriendlyName='" + attributeFriendlyName + '\''
+ "\n}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
import edu.internet2.tier.shibboleth.admin.ui.domain.AttributeValue;
import edu.internet2.tier.shibboleth.admin.ui.domain.XSAny;
import edu.internet2.tier.shibboleth.admin.ui.domain.XSBoolean;
import edu.internet2.tier.shibboleth.admin.ui.domain.XSInteger;
import edu.internet2.tier.shibboleth.admin.ui.domain.XSString;
import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects;
import org.opensaml.core.xml.schema.XSBooleanValue;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Set;

/**
* @author Bill Smith (wsmith@unicon.net)
Expand All @@ -17,43 +18,60 @@ public class AttributeUtility {

private OpenSamlObjects openSamlObjects;

private static final String URI = "urn:oasis:names:tc:SAML:2.0:attrname-format:uri";

public AttributeUtility(OpenSamlObjects openSamlObjects) {
this.openSamlObjects = openSamlObjects;
}

public edu.internet2.tier.shibboleth.admin.ui.domain.Attribute createAttributeWithBooleanValue(String name, String friendlyName, Boolean value) {
edu.internet2.tier.shibboleth.admin.ui.domain.Attribute attribute = ((edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBuilder) openSamlObjects.getBuilderFactory().getBuilder(edu.internet2.tier.shibboleth.admin.ui.domain.Attribute.DEFAULT_ELEMENT_NAME)).buildObject();
attribute.setName(name);
attribute.setFriendlyName(friendlyName);
attribute.setNameFormat("urn:oasis:names:tc:SAML:2.0:attrname-format:uri");
edu.internet2.tier.shibboleth.admin.ui.domain.Attribute attribute = createNewAttribute(name, friendlyName);

XSBoolean xsBoolean = (XSBoolean) openSamlObjects.getBuilderFactory().getBuilder(XSBoolean.TYPE_NAME).buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSBoolean.TYPE_NAME);
xsBoolean.setValue(XSBooleanValue.valueOf(value.toString()));

attribute.getAttributeValues().add(xsBoolean);

return attribute;
}

public edu.internet2.tier.shibboleth.admin.ui.domain.Attribute createAttributeWithStringValues(String name, List<String> values) {
edu.internet2.tier.shibboleth.admin.ui.domain.Attribute attribute = ((edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBuilder) openSamlObjects.getBuilderFactory()
.getBuilder(edu.internet2.tier.shibboleth.admin.ui.domain.Attribute.DEFAULT_ELEMENT_NAME)).buildObject();
attribute.setName(name);
//TODO: Do we need a friendlyName?
//TODO: Do we need a NameFormat?

values.forEach(attributeString -> {
public edu.internet2.tier.shibboleth.admin.ui.domain.Attribute createAttributeWithIntegerValue(String name, String friendlyName, Integer value) {
edu.internet2.tier.shibboleth.admin.ui.domain.Attribute attribute = createNewAttribute(name, friendlyName);

XSInteger xsInteger = (XSInteger) openSamlObjects.getBuilderFactory().getBuilder(XSInteger.TYPE_NAME).buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSInteger.TYPE_NAME);
xsInteger.setValue(value);
attribute.getAttributeValues().add(xsInteger);

return attribute;
}


public edu.internet2.tier.shibboleth.admin.ui.domain.Attribute createAttributeWithStringValues(String name, String friendlyName, String... values) {
edu.internet2.tier.shibboleth.admin.ui.domain.Attribute attribute = createNewAttribute(name, friendlyName);

for (String value : values) {
XSString xsString = (XSString) openSamlObjects.getBuilderFactory().getBuilder(XSString.TYPE_NAME).buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME);
xsString.setValue(attributeString);
xsString.setValue(value);
attribute.getAttributeValues().add(xsString);
});
}

return attribute;
}


/*
* Provided for calling with name = MDDCConstants.RELEASE_ATTRIBUTES.
*/
public edu.internet2.tier.shibboleth.admin.ui.domain.Attribute createAttributeWithStringValues(String name, List<String> values) {
return createAttributeWithStringValues(name, null, values);
}

public edu.internet2.tier.shibboleth.admin.ui.domain.Attribute createAttributeWithStringValues(String name, String friendlyName, List<String> values) {
return createAttributeWithStringValues(name, friendlyName, values.toArray(new String[]{}));
}

public edu.internet2.tier.shibboleth.admin.ui.domain.Attribute createAttributeWithArbitraryValues(String name, String friendlyName, String... values) {
edu.internet2.tier.shibboleth.admin.ui.domain.Attribute attribute = ((edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBuilder) openSamlObjects.getBuilderFactory().getBuilder(edu.internet2.tier.shibboleth.admin.ui.domain.Attribute.DEFAULT_ELEMENT_NAME)).buildObject();
attribute.setName(name);
attribute.setFriendlyName(friendlyName);
attribute.setNameFormat("urn:oasis:names:tc:SAML:2.0:attrname-format:uri");
edu.internet2.tier.shibboleth.admin.ui.domain.Attribute attribute = createNewAttribute(name, friendlyName);

for (String value : values) {
XSAny xsAny = (XSAny) openSamlObjects.getBuilderFactory().getBuilder(XSAny.TYPE_NAME).buildObject(AttributeValue.DEFAULT_ELEMENT_NAME);
Expand All @@ -68,7 +86,22 @@ public edu.internet2.tier.shibboleth.admin.ui.domain.Attribute createAttributeWi
return createAttributeWithArbitraryValues(name, friendlyName, values.toArray(new String[]{}));
}

//TODO createAttributeFromSet
// createFromNumber? XSInteger
//
public edu.internet2.tier.shibboleth.admin.ui.domain.Attribute createAttributeWithArbitraryValues(String name, String friendlyName, Set<String> values) {
return createAttributeWithStringValues(name, friendlyName, values.toArray(new String[]{}));
}


/* Calling this method with name = MDDCConstants.RELEASE_ATTRIBUTES seems to be a special case. In this case,
* we haven't been setting the friendlyName or nameFormat. Hence the null check.
*/
private edu.internet2.tier.shibboleth.admin.ui.domain.Attribute createNewAttribute(String name, String friendlyName) {
edu.internet2.tier.shibboleth.admin.ui.domain.Attribute attribute = ((edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBuilder) openSamlObjects.getBuilderFactory()
.getBuilder(edu.internet2.tier.shibboleth.admin.ui.domain.Attribute.DEFAULT_ELEMENT_NAME)).buildObject();
attribute.setName(name);
if (friendlyName != null) {
attribute.setFriendlyName(friendlyName);
attribute.setNameFormat(URI);
}
return attribute;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package edu.internet2.tier.shibboleth.admin.util;

import edu.internet2.tier.shibboleth.admin.ui.domain.Attribute;
import edu.internet2.tier.shibboleth.admin.ui.domain.RelyingPartyOverrideProperty;
import edu.internet2.tier.shibboleth.admin.ui.domain.XSBoolean;
import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.RelyingPartyOverridesRepresentation;
import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects;
Expand All @@ -9,6 +10,8 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
Expand Down Expand Up @@ -122,50 +125,71 @@ public static List<org.opensaml.saml.saml2.core.Attribute> getAttributeListFromA
}

public static List<org.opensaml.saml.saml2.core.Attribute> getAttributeListFromRelyingPartyOverridesRepresentation
(RelyingPartyOverridesRepresentation relyingPartyOverridesRepresentation) {
(List<RelyingPartyOverrideProperty> overridePropertyList,
Map<String, Object> relyingPartyOverridesRepresentation) {
List<edu.internet2.tier.shibboleth.admin.ui.domain.Attribute> list = new ArrayList<>();

if (relyingPartyOverridesRepresentation != null) {
if (relyingPartyOverridesRepresentation.isSignAssertion()) {
list.add(ATTRIBUTE_UTILITY.createAttributeWithBooleanValue(MDDCConstants.SIGN_ASSERTIONS, MDDCConstants.SIGN_ASSERTIONS_FN, true));
}
if (relyingPartyOverridesRepresentation.isDontSignResponse()) {
list.add(ATTRIBUTE_UTILITY.createAttributeWithBooleanValue(MDDCConstants.SIGN_RESPONSES, MDDCConstants.SIGN_RESPONSES_FN, false));
}
if (relyingPartyOverridesRepresentation.isTurnOffEncryption()) {
list.add(ATTRIBUTE_UTILITY.createAttributeWithBooleanValue(MDDCConstants.ENCRYPT_ASSERTIONS, MDDCConstants.ENCRYPT_ASSERTIONS_FN, false));
}
if (relyingPartyOverridesRepresentation.isUseSha()) {
list.add(ATTRIBUTE_UTILITY.createAttributeWithArbitraryValues(MDDCConstants.SECURITY_CONFIGURATION, MDDCConstants
.SECURITY_CONFIGURATION_FN, "shibboleth.SecurityConfiguration.SHA1"));
}
if (relyingPartyOverridesRepresentation.isIgnoreAuthenticationMethod()) {
// this is actually going to be wrong, but it will work for the time being. this should be a bitmask value that we calculate
// TODO: fix
list.add(ATTRIBUTE_UTILITY.createAttributeWithArbitraryValues(MDDCConstants.DISALLOWED_FEATURES, MDDCConstants.DISALLOWED_FEATURES_FN,
"0x1"));
}
if (relyingPartyOverridesRepresentation.isOmitNotBefore()) {
list.add(ATTRIBUTE_UTILITY.createAttributeWithBooleanValue(MDDCConstants.INCLUDE_CONDITIONS_NOT_BEFORE, MDDCConstants
.INCLUDE_CONDITIONS_NOT_BEFORE_FN, false));
}
if (relyingPartyOverridesRepresentation.getResponderId() != null && !"".equals(relyingPartyOverridesRepresentation.getResponderId())) {
list.add(ATTRIBUTE_UTILITY.createAttributeWithArbitraryValues(MDDCConstants.RESPONDER_ID, MDDCConstants.RESPONDER_ID_FN,
relyingPartyOverridesRepresentation.getResponderId()));
}
if (relyingPartyOverridesRepresentation.getNameIdFormats() != null && relyingPartyOverridesRepresentation.getNameIdFormats().size() > 0) {
list.add(ATTRIBUTE_UTILITY.createAttributeWithArbitraryValues(MDDCConstants.NAME_ID_FORMAT_PRECEDENCE, MDDCConstants
.NAME_ID_FORMAT_PRECEDENCE_FN, relyingPartyOverridesRepresentation.getNameIdFormats()));
}
if (relyingPartyOverridesRepresentation.getAuthenticationMethods() != null && relyingPartyOverridesRepresentation.getAuthenticationMethods().size() > 0) {
list.add(ATTRIBUTE_UTILITY.createAttributeWithArbitraryValues(MDDCConstants.DEFAULT_AUTHENTICATION_METHODS, MDDCConstants
.DEFAULT_AUTHENTICATION_METHODS_FN, relyingPartyOverridesRepresentation.getAuthenticationMethods()));
}
if (relyingPartyOverridesRepresentation.isForceAuthn()) {
list.add(ATTRIBUTE_UTILITY.createAttributeWithBooleanValue(MDDCConstants.FORCE_AUTHN, MDDCConstants.FORCE_AUTHN_FN, true));
for (Map.Entry entry : relyingPartyOverridesRepresentation.entrySet()) {
String key = (String) entry.getKey();
RelyingPartyOverrideProperty overrideProperty = overridePropertyList.stream().filter(op -> op.getDisplayName().equals(key)).findFirst().get();
switch (AttributeTypes.valueOf(overrideProperty.getDisplayType())) {
case BOOLEAN:
if (!overrideProperty.getPersistType().equals("boolean")) {
// we must be persisting a string then
list.add(ATTRIBUTE_UTILITY.createAttributeWithStringValues(overrideProperty.getAttributeName(),
overrideProperty.getAttributeFriendlyName(),
(String) entry.getValue());
} else {
list.add(ATTRIBUTE_UTILITY.createAttributeWithBooleanValue(overrideProperty.getAttributeName(),
overrideProperty.getAttributeFriendlyName(),
Boolean.valueOf((String) entry.getValue()));
}
break;
case INTEGER:
list.add(ATTRIBUTE_UTILITY.createAttributeWithIntegerValue(overrideProperty.getAttributeName(),
overrideProperty.getAttributeFriendlyName(),
Integer.valueOf((String) entry.getValue())));
break;
case STRING:
list.add(ATTRIBUTE_UTILITY.createAttributeWithStringValues(overrideProperty.getAttributeName(),
overrideProperty.getAttributeFriendlyName(),
(String) entry.getValue()));
break;
case SET:
list.add(ATTRIBUTE_UTILITY.createAttributeWithArbitraryValues(overrideProperty.getAttributeName(),
overrideProperty.getAttributeFriendlyName(),
(Set<String>) entry.getValue()));
break;
case LIST:
list.add(ATTRIBUTE_UTILITY.createAttributeWithArbitraryValues(overrideProperty.getAttributeName(),
overrideProperty.getAttributeFriendlyName(),
(List<String>) entry.getValue()));
break;
default:
throw new UnsupportedOperationException("getAttributeListFromRelyingPartyOverridesRepresentation was called with an unsupported type (" + overrideProperty.getDisplayType() + ")!");
}
}

return (List<org.opensaml.saml.saml2.core.Attribute>) (List<? extends org.opensaml.saml.saml2.core.Attribute>) list;
}


private enum AttributeTypes {
BOOLEAN("boolean"),
INTEGER("integer"),
STRING("string"),
SET("set"),
LIST("list");

private final String type;

AttributeTypes(final String type) {
this.type = type;
}

@Override
public String toString() {
return type;
}
}
}
14 changes: 13 additions & 1 deletion backend/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,17 @@ custom:
# Custom attributes

# The following contains a map of "relying party overrides".
# It is imperative when defining them that the "displayType" and "persistType" are known types.
# The structure of an entry is as follows:
# - name: The name of the entry. used to uniquely identify this entry.
# displayName: This will normally be the label used when displaying this override in the UI
# helpText: This is the help-icon hover-over text
# persistType: Optional. If it is necessary to persist something different than the override's display type,
# set that type here. For example, display a boolean, but persist a string.
# persistValue: Required only when persistType is used. Defines the value to be persisted.
# attributeName: This is the name of the attribute to be used in the xml. This is assumed to be a URI.
# attributeFriendlyName: This is the friendly name associated with the above attributeName.
#
# It is imperative when defining these that the "displayType" and "persistType" are known types.
# Typos or unsupported values here will result in that override being skipped!
# Supported types are as follows: boolean, integer, string, set, list
# Note that "persistType" doesn't have to match "displayType". However, the only unmatching combination currently
Expand All @@ -39,6 +49,8 @@ custom:
displayName: Sign the Assertion
displayType: boolean
helpText: Sign Assertion
attributeName:
attributeFriendlyName:
- name: signResponses
displayName: Don't Sign the Response
displayType: boolean
Expand Down

0 comments on commit 1837ae1

Please sign in to comment.