diff --git a/README.md b/README.md index a03a53d0b..4ec4f8196 100644 --- a/README.md +++ b/README.md @@ -47,12 +47,7 @@ The easiest way to do this in a servlet container is through the use of system p ## Authentication Currently, the application is wired with very simple authentication. A password for the user `root` -can be set with the `shibui.default-password` property. If none is set, a default password -will be generated and logged: - -``` -Using default security password: a3d9ab96-9c63-414f-b199-26fcf59e1ffa -``` +can be set with the `shibui.default-password` property. ## Default Properties diff --git a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/UserBootstrap.groovy b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/UserBootstrap.groovy index 33d93564c..4ca5b435b 100644 --- a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/UserBootstrap.groovy +++ b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/UserBootstrap.groovy @@ -46,7 +46,7 @@ class UserBootstrap { it.password = password it.firstName = firstName it.lastName = lastName - it.roles.add(role) + it.roles = [role] it.emailAddress = email it } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/auto/WebSecurityConfig.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/auto/WebSecurityConfig.java index 1dcdc6ce7..5d64ab623 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/auto/WebSecurityConfig.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/auto/WebSecurityConfig.java @@ -1,6 +1,9 @@ package edu.internet2.tier.shibboleth.admin.ui.configuration.auto; import edu.internet2.tier.shibboleth.admin.ui.security.DefaultAuditorAware; +import edu.internet2.tier.shibboleth.admin.ui.security.model.Role; +import edu.internet2.tier.shibboleth.admin.ui.security.model.User; +import edu.internet2.tier.shibboleth.admin.ui.security.repository.RoleRepository; import edu.internet2.tier.shibboleth.admin.ui.security.repository.UserRepository; import edu.internet2.tier.shibboleth.admin.ui.security.springsecurity.AdminUserService; import org.springframework.beans.factory.annotation.Autowired; @@ -23,6 +26,8 @@ import org.springframework.security.web.firewall.StrictHttpFirewall; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import java.util.Collections; + /** * Web security configuration. *

@@ -42,6 +47,9 @@ public class WebSecurityConfig { @Autowired private UserRepository userRepository; + @Autowired + private RoleRepository roleRepository; + @Bean public HttpFirewall allowUrlEncodedSlashHttpFirewall() { StrictHttpFirewall firewall = new StrictHttpFirewall(); @@ -72,6 +80,25 @@ protected void configure(AuthenticationManagerBuilder auth) throws Exception { // TODO: more configurable authentication PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); if (defaultPassword != null && !"".equals(defaultPassword)) { + // TODO: yeah, this isn't good, but we gotta initialize this user for now + User adminUser = userRepository.findByUsername("root").orElseGet(() ->{ + User u = new User(); + u.setUsername("root"); + u.setPassword(defaultPassword); + u.setFirstName("admin"); + u.setLastName("user"); + Role adminRole = roleRepository.findByName("ROLE_ADMIN").orElseGet(() -> { + Role r = new Role(); + r.setName("ROLE_ADMIN"); + return roleRepository.saveAndFlush(r); + }); + u.setRoles(Collections.singleton(adminRole)); + u.setEmailAddress("admin@localhost"); + return userRepository.saveAndFlush(u); + }); + adminUser.setPassword(defaultPassword); + userRepository.saveAndFlush(adminUser); + auth .inMemoryAuthentication() .withUser("root") diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/RelyingPartyOverrideProperty.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/RelyingPartyOverrideProperty.java index 24432d1be..1808ab6ef 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/RelyingPartyOverrideProperty.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/RelyingPartyOverrideProperty.java @@ -21,6 +21,7 @@ public class RelyingPartyOverrideProperty { private String persistValue; private String attributeName; private String attributeFriendlyName; + private String invert; @Override public String toString() { diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImpl.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImpl.java index 168e977a5..49823c008 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImpl.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImpl.java @@ -660,7 +660,7 @@ public EntityDescriptorRepresentation createRepresentationFromDescriptor(org.ope !overrideProperty.getPersistType().equals(overrideProperty.getDisplayType())) { attributeValues = overrideProperty.getPersistValue().equals(getValueFromXMLObject(jpaAttribute.getAttributeValues().get(0))); } else { - attributeValues = Boolean.valueOf(((XSBoolean) jpaAttribute.getAttributeValues() + attributeValues = Boolean.valueOf(overrideProperty.getInvert()) ^ Boolean.valueOf(((XSBoolean) jpaAttribute.getAttributeValues() .get(0)).getStoredValue()); } break; diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityServiceImpl.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityServiceImpl.java index 7d9e9388c..7afbac551 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityServiceImpl.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityServiceImpl.java @@ -94,6 +94,51 @@ public List getAttributeListFromAttributeReleaseList(List att return (List)(List)attributeList; } + edu.internet2.tier.shibboleth.admin.ui.domain.Attribute getAttributeFromObjectAndRelyingPartyOverrideProperty(Object o, RelyingPartyOverrideProperty overrideProperty) { + switch (ModelRepresentationConversions.AttributeTypes.valueOf(overrideProperty.getDisplayType().toUpperCase())) { + case BOOLEAN: + if ((o instanceof Boolean && ((Boolean)o)) || + (o instanceof String) && Boolean.valueOf((String)o)) { + if (overrideProperty.getPersistType() != null && + !overrideProperty.getPersistType().equalsIgnoreCase("boolean")) { + return attributeUtility.createAttributeWithStringValues(overrideProperty.getAttributeName(), + overrideProperty.getAttributeFriendlyName(), + overrideProperty.getPersistValue()); + } else { + if (o instanceof String) { + return attributeUtility.createAttributeWithBooleanValue(overrideProperty.getAttributeName(), + overrideProperty.getAttributeFriendlyName(), + Boolean.valueOf((String) o)); + } else { + Boolean value = Boolean.valueOf(overrideProperty.getInvert()) ^ (Boolean)o; + return attributeUtility.createAttributeWithBooleanValue(overrideProperty.getAttributeName(), + overrideProperty.getAttributeFriendlyName(), + value); + } + } + } + return null; + case INTEGER: + return attributeUtility.createAttributeWithIntegerValue(overrideProperty.getAttributeName(), + overrideProperty.getAttributeFriendlyName(), + Integer.valueOf((String) o)); + case STRING: + return attributeUtility.createAttributeWithStringValues(overrideProperty.getAttributeName(), + overrideProperty.getAttributeFriendlyName(), + (String) o); + case SET: + return attributeUtility.createAttributeWithStringValues(overrideProperty.getAttributeName(), + overrideProperty.getAttributeFriendlyName(), + (List) o); + case LIST: + return attributeUtility.createAttributeWithStringValues(overrideProperty.getAttributeName(), + overrideProperty.getAttributeFriendlyName(), + (List) o); + default: + throw new UnsupportedOperationException("getAttributeListFromRelyingPartyOverridesRepresentation was called with an unsupported type (" + overrideProperty.getDisplayType() + ")!"); + } + } + @Override public List getAttributeListFromRelyingPartyOverridesRepresentation(Map relyingPartyOverridesRepresentation) { List overridePropertyList = customPropertiesConfiguration.getOverrides(); @@ -102,50 +147,9 @@ public List getAttributeListFromRelyingPartyOverridesRepresentation(M for (Map.Entry entry : relyingPartyOverridesRepresentation.entrySet()) { String key = (String) entry.getKey(); RelyingPartyOverrideProperty overrideProperty = overridePropertyList.stream().filter(op -> op.getName().equals(key)).findFirst().get(); - switch (ModelRepresentationConversions.AttributeTypes.valueOf(overrideProperty.getDisplayType().toUpperCase())) { - case BOOLEAN: - if ((entry.getValue() instanceof Boolean && (Boolean)entry.getValue()) || - ((entry.getValue() instanceof String) && Boolean.valueOf((String)entry.getValue()))) { - if (overrideProperty.getPersistType() != null && - !overrideProperty.getPersistType().equalsIgnoreCase("boolean")) { - list.add(attributeUtility.createAttributeWithStringValues(overrideProperty.getAttributeName(), - overrideProperty.getAttributeFriendlyName(), - overrideProperty.getPersistValue())); - } else { - if (entry.getValue() instanceof String) { - list.add(attributeUtility.createAttributeWithBooleanValue(overrideProperty.getAttributeName(), - overrideProperty.getAttributeFriendlyName(), - Boolean.valueOf((String) entry.getValue()))); - } else { - list.add(attributeUtility.createAttributeWithBooleanValue(overrideProperty.getAttributeName(), - overrideProperty.getAttributeFriendlyName(), - (Boolean) entry.getValue())); - } - } - } - break; - case INTEGER: - list.add(attributeUtility.createAttributeWithIntegerValue(overrideProperty.getAttributeName(), - overrideProperty.getAttributeFriendlyName(), - Integer.valueOf((String) entry.getValue()))); - break; - case STRING: - list.add(attributeUtility.createAttributeWithStringValues(overrideProperty.getAttributeName(), - overrideProperty.getAttributeFriendlyName(), - (String) entry.getValue())); - break; - case SET: - list.add(attributeUtility.createAttributeWithStringValues(overrideProperty.getAttributeName(), - overrideProperty.getAttributeFriendlyName(), - (List) entry.getValue())); - break; - case LIST: - list.add(attributeUtility.createAttributeWithStringValues(overrideProperty.getAttributeName(), - overrideProperty.getAttributeFriendlyName(), - (List) entry.getValue())); - break; - default: - throw new UnsupportedOperationException("getAttributeListFromRelyingPartyOverridesRepresentation was called with an unsupported type (" + overrideProperty.getDisplayType() + ")!"); + edu.internet2.tier.shibboleth.admin.ui.domain.Attribute attribute = getAttributeFromObjectAndRelyingPartyOverrideProperty(entry.getValue(), overrideProperty); + if (attribute != null) { + list.add(attribute); } } diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 12bfd55cc..8e823e8a3 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -61,6 +61,7 @@ custom: helpText: tooltip.dont-sign-response attributeName: http://shibboleth.net/ns/profiles/saml2/sso/browser/signResponses attributeFriendlyName: signResponses + invert: true - name: turnOffEncryption displayName: label.turn-off-encryption-of-response displayType: boolean @@ -68,6 +69,7 @@ custom: helpText: tooltip.turn-off-encryption attributeName: http://shibboleth.net/ns/profiles/encryptAssertions attributeFriendlyName: encryptAssertions + invert: true - name: useSha displayName: label.use-sha1-signing-algorithm displayType: boolean @@ -93,6 +95,7 @@ custom: helpText: tooltip.omit-not-before-condition attributeName: http://shibboleth.net/ns/profiles/includeConditionsNotBefore attributeFriendlyName: includeConditionsNotBefore + invert: true - name: responderId displayName: label.responder-id displayType: string diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/AuxiliaryJPAEntityServiceTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/AuxiliaryJPAEntityServiceTests.groovy new file mode 100644 index 000000000..92c2627aa --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/AuxiliaryJPAEntityServiceTests.groovy @@ -0,0 +1,45 @@ +package edu.internet2.tier.shibboleth.admin.ui.service + +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.opensaml.OpenSamlObjects +import edu.internet2.tier.shibboleth.admin.util.AttributeUtility +import spock.lang.Shared +import spock.lang.Specification +import spock.lang.Unroll + +class AuxiliaryJPAEntityServiceTests extends Specification { + @Shared + JPAEntityServiceImpl jpaEntityService + + def setup() { + def openSamlObjects = new OpenSamlObjects().with { + it.init() + it + } + + def attributeUtility = new AttributeUtility(openSamlObjects) + + jpaEntityService = new JPAEntityServiceImpl(openSamlObjects, attributeUtility) + } + + @Unroll + def "test invert #input"() { + setup: + RelyingPartyOverrideProperty overrideProperty = new RelyingPartyOverrideProperty( + attributeName: 'name', + attributeFriendlyName: 'friendlyName', + displayType: 'boolean', + invert: 'true' + ) + Attribute att = jpaEntityService.getAttributeFromObjectAndRelyingPartyOverrideProperty(input, overrideProperty) + + expect: + assert att && att.getAttributeValues()[0] instanceof XSBoolean && ((XSBoolean) att.getAttributeValues()[0]).value.value == output + + where: + input | output + true | false + } +}