Skip to content

Commit

Permalink
SHIBUI-2380
Browse files Browse the repository at this point in the history
Incremental commit:
- OauthRPExtension built completely from XML upload (marshall and unmarshall complete)
- Representation updated for UI output (accepting for build from UI still TODO)
  • Loading branch information
chasegawa committed Sep 19, 2022
1 parent 2d9dfdd commit e63841d
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,31 +1,26 @@
package edu.internet2.tier.shibboleth.admin.ui.domain.frontend;

import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Getter
@Setter
public class ServiceProviderSsoDescriptorRepresentation implements Serializable {


private static final long serialVersionUID = 8366502466924209389L;

private String protocolSupportEnum;

private List<String> nameIdFormats = new ArrayList<>();

public String getProtocolSupportEnum() {
return protocolSupportEnum;
}

public void setProtocolSupportEnum(String protocolSupportEnum) {
this.protocolSupportEnum = protocolSupportEnum;
}

public List<String> getNameIdFormats() {
return nameIdFormats;
}
private Map<String,Object> extensions = new HashMap<>();

public void setNameIdFormats(List<String> nameIdFormats) {
this.nameIdFormats = nameIdFormats;
public void addExtensions(String name, Map<String, Object> value) {
extensions.put(name, value);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractXMLObject;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.hibernate.envers.Audited;
import org.opensaml.core.xml.XMLObject;
Expand All @@ -20,9 +21,13 @@

@Entity
@Data
@EqualsAndHashCode(callSuper=false)
@NoArgsConstructor
@Audited
public class OAuthRPExtensions extends AbstractXMLObject implements net.shibboleth.oidc.saml.xmlobject.OAuthRPExtensions {
public static final String DEFAULT_ELEMENT_LOCAL_NAME = TYPE_LOCAL_NAME;

// Only support the attributes used by Shib 4.x - https://shibboleth.atlassian.net/wiki/spaces/SC/pages/1912406916/OAuthRPMetadataProfile
@Transient
private final AttributeMap unknownAttributes = new AttributeMap(this);

Expand Down Expand Up @@ -83,9 +88,57 @@ public class OAuthRPExtensions extends AbstractXMLObject implements net.shibbole

private String userInfoEncryptedResponseEnc;

@Override
public List<XMLObject> getOrderedChildren() {
List<XMLObject> result = new ArrayList<>();
result.addAll(defaultAcrValues);
result.addAll(requestUris);
result.addAll(postLogoutRedirectUris);
result.addAll(unknownXMLObjects);
return result;
}

@Override
public List<XMLObject> getUnknownXMLObjects() {
return this.unknownXMLObjects.stream().filter(p -> true).collect(Collectors.toList());
}

@Nonnull
@Override
public List<XMLObject> getUnknownXMLObjects(@Nonnull QName typeOrName) {
return this.unknownXMLObjects.stream().filter(p -> p.getElementQName().equals(typeOrName) || p.getSchemaType().equals(typeOrName)).collect(Collectors.toList());
}

@Override
public List<net.shibboleth.oidc.saml.xmlobject.PostLogoutRedirectUri> getPostLogoutRedirectUris() {
List<net.shibboleth.oidc.saml.xmlobject.PostLogoutRedirectUri> result = new ArrayList<>();
result.addAll(postLogoutRedirectUris);
return result;
}

@Override
public List<net.shibboleth.oidc.saml.xmlobject.DefaultAcrValue> getDefaultAcrValues() {
List<net.shibboleth.oidc.saml.xmlobject.DefaultAcrValue> result = new ArrayList<>();
result.addAll(defaultAcrValues);
return result;
}

@Override
public List<net.shibboleth.oidc.saml.xmlobject.RequestUri> getRequestUris() {
List<net.shibboleth.oidc.saml.xmlobject.RequestUri> result = new ArrayList<>();
result.addAll(requestUris);
return result;
}

public void addDefaultAcrValue(DefaultAcrValue childSAMLObject) {
defaultAcrValues.add(childSAMLObject);
}

public void addRequestUri(RequestUri childSAMLObject) {
requestUris.add(childSAMLObject);
}

public void addPostLogoutRedirectUri(PostLogoutRedirectUri childSAMLObject) {
postLogoutRedirectUris.add(childSAMLObject);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package edu.internet2.tier.shibboleth.admin.ui.domain.oidc;

import net.shibboleth.oidc.saml.xmlobject.OAuthRPExtensions;
import org.opensaml.core.xml.XMLObject;
import org.opensaml.core.xml.io.MarshallingException;
import org.opensaml.saml.common.AbstractSAMLObjectMarshaller;
Expand Down Expand Up @@ -122,6 +121,10 @@ protected void marshallAttributes(final XMLObject samlElement, final Element dom
domElement.setAttributeNS(null, REQUIRE_AUTH_TIME_ATTRIB_NAME, Boolean.toString(extensions.isRequireAuthTime()));
}

for (XMLObject xmlObject: extensions.getOrderedChildren()) {
marshallChildElements(xmlObject, domElement);
}

marshallUnknownAttributes(extensions, domElement);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package edu.internet2.tier.shibboleth.admin.ui.domain.oidc;

import net.shibboleth.oidc.saml.xmlobject.DefaultAcrValue;
import net.shibboleth.oidc.saml.xmlobject.OAuthRPExtensions;
import net.shibboleth.oidc.saml.xmlobject.PostLogoutRedirectUri;
import net.shibboleth.oidc.saml.xmlobject.RequestUri;
import org.apache.commons.lang3.StringUtils;
import org.opensaml.core.xml.XMLObject;
import org.opensaml.core.xml.io.UnmarshallingException;
Expand Down Expand Up @@ -38,11 +34,11 @@ protected void processChildElement(final XMLObject parentSAMLObject, final XMLOb
final OAuthRPExtensions extensions = (OAuthRPExtensions) parentSAMLObject;

if (childSAMLObject instanceof DefaultAcrValue) {
extensions.getDefaultAcrValues().add((DefaultAcrValue) childSAMLObject);
extensions.addDefaultAcrValue((DefaultAcrValue) childSAMLObject);
} else if (childSAMLObject instanceof RequestUri) {
extensions.getRequestUris().add((RequestUri) childSAMLObject);
extensions.addRequestUri((RequestUri) childSAMLObject);
} else if (childSAMLObject instanceof PostLogoutRedirectUri) {
extensions.getPostLogoutRedirectUris().add((PostLogoutRedirectUri) childSAMLObject);
extensions.addPostLogoutRedirectUri((PostLogoutRedirectUri) childSAMLObject);
} else {
extensions.getUnknownXMLObjects().add(childSAMLObject);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.OrganizationRepresentation;
import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.SecurityInfoRepresentation;
import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.ServiceProviderSsoDescriptorRepresentation;
import edu.internet2.tier.shibboleth.admin.ui.domain.oidc.OAuthRPExtensions;
import edu.internet2.tier.shibboleth.admin.ui.domain.oidc.ValueXMLObject;
import edu.internet2.tier.shibboleth.admin.ui.exception.PersistentEntityNotFound;
import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException;
Expand Down Expand Up @@ -48,7 +49,6 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opensaml.core.xml.XMLObject;
import org.opensaml.saml.saml2.metadata.KeyDescriptor;
import org.opensaml.xmlsec.signature.KeyInfo;
import org.opensaml.xmlsec.signature.KeyName;
import org.opensaml.xmlsec.signature.KeyValue;
Expand Down Expand Up @@ -104,6 +104,59 @@ private EntityDescriptor buildDescriptorFromRepresentation(final EntityDescripto
return ed;
}

/**
* Currently only supporting oidcmd:OAuthRPExtensions in the extensions block
*/
private Map<String, Object> buildOAuthRPExtensionsMap(EntityDescriptor ed) {
HashMap<String, Object> result = new HashMap<>();
for(XMLObject extension : ed.getSPSSODescriptor("").getExtensions().getOrderedChildren()) {
if (extension.getElementQName().getLocalPart().equals(OAuthRPExtensions.TYPE_LOCAL_NAME)){
OAuthRPExtensions oAuthRPExtensions = (OAuthRPExtensions) extension;
HashMap<String, Object> attributeMap = new HashMap();
attributeMap.put("applicationType", oAuthRPExtensions.getApplicationType());
attributeMap.put("clientUri", oAuthRPExtensions.getClientUri());
attributeMap.put("defaultMaxAge", oAuthRPExtensions.getDefaultMaxAge());
attributeMap.put("grantTypes", oAuthRPExtensions.getGrantTypes());
attributeMap.put("idTokenEncryptedResponseAlg", oAuthRPExtensions.getIdTokenEncryptedResponseAlg());
attributeMap.put("idTokenEncryptedResponseEnc", oAuthRPExtensions.getIdTokenEncryptedResponseEnc());
attributeMap.put("idTokenSignedResponseAlg", oAuthRPExtensions.getIdTokenSignedResponseAlg());
attributeMap.put("initiateLoginUri", oAuthRPExtensions.getInitiateLoginUri());
attributeMap.put("requestObjectEncryptionAlg", oAuthRPExtensions.getRequestObjectEncryptionAlg());
attributeMap.put("requestObjectEncryptionEnc", oAuthRPExtensions.getRequestObjectEncryptionEnc());
attributeMap.put("requestObjectSigningAlg", oAuthRPExtensions.getRequestObjectSigningAlg());
attributeMap.put("requireAuthTime", oAuthRPExtensions.isRequireAuthTime());
attributeMap.put("responseTypes", oAuthRPExtensions.getResponseTypes());
attributeMap.put("scopes", oAuthRPExtensions.getScopes());
attributeMap.put("sectorIdentifierUri", oAuthRPExtensions.getSectorIdentifierUri());
attributeMap.put("softwareId", oAuthRPExtensions.getSoftwareId());
attributeMap.put("softwareVersion", oAuthRPExtensions.getSoftwareVersion());
attributeMap.put("tokenEndpointAuthMethod", oAuthRPExtensions.getTokenEndpointAuthMethod());
attributeMap.put("tokenEndpointAuthSigningAlg", oAuthRPExtensions.getTokenEndpointAuthSigningAlg());
attributeMap.put("userInfoSignedResponseAlg", oAuthRPExtensions.getUserInfoSignedResponseAlg());
attributeMap.put("userInfoEncryptedResponseAlg", oAuthRPExtensions.getUserInfoEncryptedResponseAlg());
attributeMap.put("userInfoEncryptedResponseEnc", oAuthRPExtensions.getUserInfoEncryptedResponseEnc());
result.put("attributes", attributeMap);
// spit out the children
if (oAuthRPExtensions.getRequestUris().size() > 0){
List<String> requestUris = new ArrayList<>();
oAuthRPExtensions.getRequestUris().forEach(requestUri -> requestUris.add(requestUri.getValue()));
result.put("requestUris", requestUris);
}
if (oAuthRPExtensions.getPostLogoutRedirectUris().size() > 0){
List<String> postLogoutRedirectUris = new ArrayList<>();
oAuthRPExtensions.getPostLogoutRedirectUris().forEach(redirectUri -> postLogoutRedirectUris.add(redirectUri.getValue()));
result.put("postLogoutRedirectUris", postLogoutRedirectUris);
}
if (oAuthRPExtensions.getDefaultAcrValues().size() > 0){
List<String> defaultAcrValues = new ArrayList<>();
oAuthRPExtensions.getDefaultAcrValues().forEach(acrValue -> defaultAcrValues.add(acrValue.getValue()));
result.put("defaultAcrValues", defaultAcrValues);
}
}
}
return result;
}

@Override
public EntityDescriptor createDescriptorFromRepresentation(final EntityDescriptorRepresentation representation) {
EntityDescriptor ed = openSamlObjects.buildDefaultInstanceOfType(EntityDescriptor.class);
Expand All @@ -123,17 +176,12 @@ public EntityDescriptorRepresentation createNewEntityDescriptorFromXMLOrigin(Ent
return createRepresentationFromDescriptor(savedEntity);
}

// Change to check for OAuthRPExtensions in the extensions?
private EntityDescriptorProtocol determineEntityDescriptorProtocol(EntityDescriptor ed) {
boolean oidcType = false;
if (ed.getSPSSODescriptor("") != null && ed.getSPSSODescriptor("").getKeyDescriptors().size() > 0) {
for (KeyDescriptor keyDescriptor : ed.getSPSSODescriptor("").getKeyDescriptors()) {
KeyInfo keyInfo = keyDescriptor.getKeyInfo();
KeyDescriptorRepresentation.ElementType keyInfoType = determineKeyInfoType(keyInfo);
if (keyInfoType == KeyDescriptorRepresentation.ElementType.clientSecret || keyInfoType == KeyDescriptorRepresentation.ElementType.clientSecretKeyReference ||
keyInfoType == KeyDescriptorRepresentation.ElementType.jwksData || keyInfoType == KeyDescriptorRepresentation.ElementType.jwksUri) {
if (ed.getSPSSODescriptor("") != null && ed.getSPSSODescriptor("").getExtensions().getOrderedChildren().size() > 0) {
for (XMLObject e : ed.getSPSSODescriptor("").getExtensions().getOrderedChildren()) {
if (e.getElementQName().getLocalPart().equals(OAuthRPExtensions.TYPE_LOCAL_NAME)) {
oidcType = true;
break;
}
}
}
Expand Down Expand Up @@ -195,6 +243,7 @@ public EntityDescriptorRepresentation createRepresentationFromDescriptor(org.ope
representation.setIdOfOwner(ed.getIdOfOwner());
representation.setProtocol(ed.getProtocol());

// Set up SPSSODescriptor
if (ed.getSPSSODescriptor("") != null && ed.getSPSSODescriptor("").getSupportedProtocols().size() > 0) {
ServiceProviderSsoDescriptorRepresentation serviceProviderSsoDescriptorRepresentation = representation.getServiceProviderSsoDescriptor(true);
serviceProviderSsoDescriptorRepresentation.setProtocolSupportEnum(String.join(",", ed.getSPSSODescriptor("").getSupportedProtocols().stream().map(p -> MDDCConstants.PROTOCOL_BINDINGS.get(p)).collect(Collectors.toList())));
Expand All @@ -207,6 +256,11 @@ public EntityDescriptorRepresentation createRepresentationFromDescriptor(org.ope
);
}

if (ed.getSPSSODescriptor("") != null && ed.getProtocol() == EntityDescriptorProtocol.OIDC) {
ServiceProviderSsoDescriptorRepresentation serviceProviderSsoDescriptorRepresentation = representation.getServiceProviderSsoDescriptor(true);
serviceProviderSsoDescriptorRepresentation.addExtensions("OAuthRPExtensions", buildOAuthRPExtensionsMap(ed));
}

if (ed.getOrganization() != null) {
// set up organization
OrganizationRepresentation organizationRepresentation = new OrganizationRepresentation();
Expand Down

0 comments on commit e63841d

Please sign in to comment.