diff --git a/Jenkinsfile b/Jenkinsfile index 09dc3d946..dc2a92cae 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -36,7 +36,7 @@ pipeline { steps { sh ''' docker stop shibui || true && docker rm shibui || true - docker run -d --restart always --name shibui -p 8080:8080 -v /etc/shibui/application.properties:/application.properties unicon/shibui:latest + docker run -d --restart always --name shibui -p 8080:8080 -v /etc/shibui/application.properties:/application.properties -m 3GB --memory-swap=3GB unicon/shibui:latest ''' } } diff --git a/backend/build.gradle b/backend/build.gradle index bf62e58c7..f3204d4f6 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -77,6 +77,9 @@ dependencies { // TODO: figure out what this should really be runtimeOnly 'org.springframework.boot:spring-boot-starter-tomcat' + //Spring Configuration Annotation Processor - makes IntelliJ happy about @ConfigurationProperties + compileOnly "org.springframework.boot:spring-boot-configuration-processor" + // lucene deps ['core', 'analyzers-common', 'queryparser'].each { compile "org.apache.lucene:lucene-${it}:${project.'lucene.version'}" @@ -218,4 +221,4 @@ docker { noCache true files tasks.bootWar.outputs buildArgs(['JAR_FILE': 'shibui.war']) -} \ No newline at end of file +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java index e17c33b0e..105c1ddf6 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java @@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ResourceBundleMessageSource; @@ -42,6 +43,7 @@ import javax.servlet.http.HttpServletRequest; @Configuration +@EnableConfigurationProperties(CustomAttributesConfiguration.class) public class CoreShibUiConfiguration { private static final Logger logger = LoggerFactory.getLogger(CoreShibUiConfiguration.class); @@ -170,6 +172,11 @@ public LuceneUtility luceneUtility(DirectoryService directoryService) { return new LuceneUtility(directoryService); } + @Bean + public CustomAttributesConfiguration customAttributesConfiguration() { + return new CustomAttributesConfiguration(); + } + @Bean public Module stringTrimModule() { return new StringTrimModule(); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CustomAttributesConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CustomAttributesConfiguration.java new file mode 100644 index 000000000..aa12be6b2 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CustomAttributesConfiguration.java @@ -0,0 +1,26 @@ +package edu.internet2.tier.shibboleth.admin.ui.configuration; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @author Bill Smith (wsmith@unicon.net) + */ +@Configuration +@ConfigurationProperties(prefix="custom") +public class CustomAttributesConfiguration { + + private List> attributes = new ArrayList<>(); + + public List> getAttributes() { + return attributes; + } + + public void setAttributes(List> attributes) { + this.attributes = attributes; + } +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/ConfigurationController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/ConfigurationController.java new file mode 100644 index 000000000..4a0388428 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/ConfigurationController.java @@ -0,0 +1,24 @@ +package edu.internet2.tier.shibboleth.admin.ui.controller; + +import edu.internet2.tier.shibboleth.admin.ui.configuration.CustomAttributesConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * @author Bill Smith (wsmith@unicon.net) + */ +@Controller +@RequestMapping(value = "/api") +public class ConfigurationController { + + @Autowired + CustomAttributesConfiguration customAttributesConfiguration; + + @GetMapping(value = "/customAttributes") + public ResponseEntity getCustomAttributes() { + return ResponseEntity.ok(customAttributesConfiguration.getAttributes()); + } +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/ModelRepresentationConversions.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/ModelRepresentationConversions.java index 27fd92445..e68225b5a 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/ModelRepresentationConversions.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/ModelRepresentationConversions.java @@ -47,14 +47,11 @@ public static List getAttributeReleaseListFromAttributeList(List attribute.getName().equals(MDDCConstants.RELEASE_ATTRIBUTES)) .collect(Collectors.toList()); - if (releaseAttributes.size() != 1) { - // TODO: What do we do if there is more than one? - } - if (releaseAttributes.size() == 0) { - return new ArrayList<>(); - } else { - return getStringListOfAttributeValues(releaseAttributes.get(0).getAttributeValues()); + List attributeValues = new ArrayList<>(); + for (Attribute attribute : releaseAttributes) { + attributeValues.addAll(getStringListOfAttributeValues(attribute.getAttributeValues())); } + return attributeValues; } public static boolean getBooleanValueOfAttribute(Attribute attribute) { diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml new file mode 100644 index 000000000..563d01073 --- /dev/null +++ b/backend/src/main/resources/application.yml @@ -0,0 +1,28 @@ +custom: + attributes: + # Default attributes + - name: eduPersonPrincipalName + displayName: label.attribute-eduPersonPrincipalName + - name: uid + displayName: label.attribute-uid + - name: mail + displayName: label.attribute-mail + - name: surname + displayName: label.attribute-surname + - name: givenName + displayName: label.attribute-givenName + - name: eduPersonAffiliation + displayName: label.attribute-eduPersonAffiliation + - name: eduPersonScopedAffiliation + displayName: label.attribute-eduPersonScopedAffiliation + - name: eduPersonPrimaryAffiliation + displayName: label.attribute-eduPersonPrimaryAffiliation + - name: eduPersonEntitlement + displayName: label.attribute-eduPersonEntitlement + - name: eduPersonAssurance + displayName: label.attribute-eduPersonAssurance + - name: eduPersonUniqueId + displayName: label.attribute-eduPersonUniqueId + - name: employeeNumber + displayName: label.attribute-employeeNumber + # Custom attributes diff --git a/backend/src/main/resources/i18n/messages_en.properties b/backend/src/main/resources/i18n/messages_en.properties index 2c6a755ab..2dec2872d 100644 --- a/backend/src/main/resources/i18n/messages_en.properties +++ b/backend/src/main/resources/i18n/messages_en.properties @@ -8,7 +8,7 @@ action.clear=Clear action.delete=Delete action.remove=Remove action.save=Save -action.toggle=Toggle { label } +action.toggle=Toggle action.add-contact=Add Contact action.add-contacts=Add Contacts action.use-mine=Use My Changes @@ -31,6 +31,12 @@ action.choose-file=Choose File action.search-by=Search By action.preview=Preview action.select-metadata-filter-type=Select a metadata filter type +action.add-authentication-method=Add Authentication Method +action.move-up=Move Up +action.move-down=Move Down +action.edit=Edit +action.add-filter=Add Filter +action.manage-filters=Manage Filters value.enabled=Enabled value.disabled=Disabled @@ -39,6 +45,9 @@ value.file=File value.memory=Memory value.true=True value.false=False +value.regex=Regex +value.script=Script +value.entity-id=Entity ID value.file-backed-http-metadata-provider=FileBackedHttpMetadataProvider value.entity-attributes-filter=EntityAttributes Filter @@ -139,7 +148,7 @@ label.contact-name=Contact Name label.select-contact-type=Select Contact Type label.contact-email-address=Contact Email Address label.sign-the-assertion=Sign the Assertion -label.dont-sign-the-response=Don''t Sign the Response +label.dont-sign-the-response=Don\u0027t Sign the Response label.turn-off-encryption-of-response=Turn Off Encryption of Response label.use-sha1-signing-algorithm=Use SHA1 Signing Algorithm label.nameid-format-to-send=NameID Format to Send @@ -201,10 +210,11 @@ label.service-enabled=Service Enabled label.filter-name=Filter Name label.filter-enabled=Filter Enabled label.filter-target=FilterTarget +label.filter-type=Filter Type label.value=Value label.binding-type=Binding Type label.sign-assertion=Sign Assertions -label.dont-sign-response=Don''t Sign Response +label.dont-sign-response=Don\u0027t Sign Response label.turn-off-encryption=Turn off encryption label.use-sha=Use Sha label.ignore-authentication-method=Ignore Authentication Method @@ -223,13 +233,12 @@ label.binding=Binding label.location-url=Location URL label.make-default=Make Default label.metadata-provider-name-dashboard-display-only=Metadata Provider Name (Dashboard Display Only) +label.default-authentication-methods=Default Authentication Method(s) label.filter-name=Filter Name (Dashboard Display Only) label.metadata-filter-name=Metadata Filter Name (Dashboard Display Only) label.filter-enable=Enable this Filter? label.search-criteria=Search Criteria -label.regex=Regex -label.script=Script label.metadata-filter=Metadata Filter label.metadata-filter-type=Metadata Filter Type @@ -270,10 +279,12 @@ label.metadata-url=Metadata URL label.xml-id=ID label.enable-service=Enable this service? label.metadata-provider-type=Metadata Provider Type -label.metadata-provider-name=Metadata Provider Name (Dashboard Display Only) +label.metadata-provider-name=Metadata Provider Name label.select-metadata-type=Select a metadata provider type +label.metadata-provider-status=Metadata Provider Status label.enable-provider-upon-saving=Enable Metadata Provider upon saving? +label.enable-filter=Enable Filter? label.required-valid-until=Required Valid Until Filter label.max-validity-interval=Max Validity Interval label.signature-validation-filter=Signature Validation Filter @@ -284,7 +295,38 @@ label.retained-roles=Retained Roles label.remove-roleless-entity-descriptors=Remove Roleless Entity Descriptors? label.remove-empty-entities-descriptors=Remove Empty Entities Descriptors? +label.select-metadata-provider-type=Select Metadata Provider Type +label.filter-list=Filter List +label.common-attributes=Common Attributes +label.reloading-attributes=Reloading Attributes +label.metadata-filter-plugins=Metadata Filter Plugins +label.advanced-settings=Advanced Settings +label.edit-metadata-provider=Edit Metadata Provider + +label.metadata-ui=User Interface / MDUI Information +label.descriptor-info=SP SSO Descriptor Information +label.key-info=Security Information +label.assertion=Assertion Consumer Service +label.relying-party=Relying Party Overrides +label.org-info=Organization Information + +label.attribute-eduPersonPrincipalName=eduPersonPrincipalName (EPPN) +label.attribute-uid=uid +label.attribute-mail=mail +label.attribute-surname=surname +label.attribute-givenName=givenName +label.attribute-eduPersonAffiliation=eduPersonAffiliation +label.attribute-eduPersonScopedAffiliation=eduPersonScopedAffiliation +label.attribute-eduPersonPrimaryAffiliation=eduPersonPrimaryAffiliation +label.attribute-eduPersonEntitlement=eduPersonEntitlement +label.attribute-eduPersonAssurance=eduPersonAssurance +label.attribute-eduPersonUniqueId=eduPersonUniqueId +label.attribute-employeeNumber=employeeNumber + message.must-be-unique=Must be unique. +message.name-must-be-unique=Name must be unique. +message.uri-valid-format=URI must be valid format. +message.id-unique=ID must be unique. message.conflict=Conflict message.data-version-contention=Data Version Contention @@ -302,14 +344,14 @@ message.delete-filter-body=You are deleting a metadata filter. This cannot be un message.unsaved-dialog-title=Save your information? message.unsaved-editor=You have not saved your changes. If you exit this screen, your changes will be lost. message.editor-invalid=All forms must be valid before changes can be saved! -message.unsaved-source-1=You have not completed the wizard! Do you wish to save this information? You can finish the wizard later by clicking the ''Edit'' +message.unsaved-source-1=You have not completed the wizard! Do you wish to save this information? You can finish the wizard later by clicking the \u0027Edit\u0027 message.unsaved-source-2=icon on the dashboard. message.service-resolver-name-required=Service Resolver Name is required message.entity-id-required=Entity ID is required message.entity-id-must-be-unique=Entity ID must be unique message.file-upload-alert=Note: You can only import a file with a single entityID (EntityDescriptor element) in it. Anything more in that file will result in an error. message.add-new-md-resolver=Add a new metadata source -message.wizard-status=Step { index } of {{ length }} +message.wizard-status=Step { index } of { length } message.entity-id-min-unique=You must add at least one entity id target and they must each be unique. message.required-for-scripts=Required for Scripts message.required-for-regex=Required for Regex @@ -338,7 +380,7 @@ tooltip.logout-endpoints-binding-type=Logout Endpoints Binding Type tooltip.mdui-display-name=Typically, the IdP Display Name field will be presented on IdP discovery service interfaces. tooltip.mdui-information-url=The IdP Information URL is a link to a comprehensive information page about the IdP. This page should expand on the content of the IdP Description field. tooltip.mdui-description=The IdP Description is a brief description of the IdP service. On a well-designed discovery interface, the IdP Description will be presented to the user in addition to the IdP Display Name, and so the IdP Description helps disambiguate duplicate or similar IdP Display Names. -tooltip.mdui-privacy-statement-url=The IdP Privacy Statement URL is a link to the IdP''s Privacy Statement. The content of the Privacy Statement should be targeted at end users. +tooltip.mdui-privacy-statement-url=The IdP Privacy Statement URL is a link to the IdP\u0027s Privacy Statement. The content of the Privacy Statement should be targeted at end users. tooltip.mdui-logo-url=The IdP Logo URL in metadata points to an image file on a remote server. A discovery service, for example, may rely on a visual cue (i.e., a logo) instead of or in addition to the IdP Display Name. tooltip.mdui-logo-width=The logo should have a minimum width of 100 pixels tooltip.mdui-logo-height=The logo should have a minimum height of 75 pixels and a maximum height of 150 pixels (or the application will scale it proportionally) @@ -346,12 +388,12 @@ tooltip.organization-name=Organization Name tooltip.organization-display-name=Organization Display Name tooltip.organization-url=Organization Url tooltip.contact-name=Contact Name +tooltip.contact-type=Contact Type tooltip.contact-email=Contact Email tooltip.sign-assertion=Sign Assertion -tooltip.dont-sign-response=Don''t Sign Response +tooltip.dont-sign-response=Don\u0027t Sign Response tooltip.turn-off-encryption=Turn Off Encryption of Response tooltip.usa-sha-algorithm=Use SHA1 Signing Algorithm -tooltip.nameid-format=Add NameID Format tooltip.authentication-methods-to-use=Authentication Methods to Use tooltip.ignore-auth-method=Ignore any SP-Requested Authentication Method tooltip.omit-not-before-condition=Omit Not Before Condition @@ -360,8 +402,8 @@ tooltip.instruction=Information icon - press spacebar to read additional informa tooltip.attribute-release-table=Attribute release table - select the attributes you want to release (default unchecked) tooltip.metadata-filter-name=Metadata Filter Name tooltip.metadata-filter-type=Metadata Filter Type -tooltip.connection-request-timeout=The maximum amount of time to wait for a connection to be returned from the HTTP client''s connection pool manager. Set to PT0S to disable. This attribute is incompatible with httpClientRef. -tooltip.connection-timout=The maximum amount of time to wait to establish a connection with the remote server. Set to PT0S to disable. This attribute is incompatible with httpClientRef. +tooltip.connection-request-timeout=The maximum amount of time to wait for a connection to be returned from the HTTP client\u0027s connection pool manager. Set to PT0S to disable. This attribute is incompatible with httpClientRef. +tooltip.connection-timeout=The maximum amount of time to wait to establish a connection with the remote server. Set to PT0S to disable. This attribute is incompatible with httpClientRef. tooltip.socket-timeout=The maximum amount of time to wait between two consecutive packets while reading from the socket connected to the remote server. Set to PT0S to disable. This attribute is incompatible with httpClientRef. tooltip.disregard-tls-cert=If true, no TLS certificate checking will take place over an HTTPS connection. This attribute is incompatible with httpClientRef. (Be careful with this setting, it is typically only used during testing. See the HttpClientConfiguration topic for more information.) tooltip.proxy-host=The hostname of the HTTP proxy through which connections will be made. This attribute is incompatible with httpClientRef. @@ -393,8 +435,12 @@ tooltip.retained-roles=Retained Roles tooltip.remove-roleless-entity-descriptors=Controls whether to keep entity descriptors that contain no roles. tooltip.remove-empty-entities-descriptors=Controls whether to keep entities descriptors that contain no entity descriptors. -tooltip.min-refresh-delay=Lower bound on the next refresh from the time calculated based on the metadata''s expiration. -tooltip.max-refresh-delay=Upper bound on the next refresh from the time calculated based on the metadata''s expiration. -tooltip.refresh-delay-factor=A factor applied to the initially determined refresh time in order to determine the next refresh time (typically to ensure refresh takes place prior to the metadata''s expiration). Attempts to refresh metadata will generally begin around the product of this number and the maximum refresh delay. +tooltip.min-refresh-delay=Lower bound on the next refresh from the time calculated based on the metadata\u0027s expiration. +tooltip.max-refresh-delay=Upper bound on the next refresh from the time calculated based on the metadata\u0027s expiration. +tooltip.refresh-delay-factor=A factor applied to the initially determined refresh time in order to determine the next refresh time (typically to ensure refresh takes place prior to the metadata\u0027s expiration). Attempts to refresh metadata will generally begin around the product of this number and the maximum refresh delay. tooltip.resolve-via-predicates-only=Flag indicating whether resolution may be performed solely by applying predicates to the entire metadata collection, when an entityID input criterion is not supplied. tooltip.expiration-warning-threshold=For each attempted metadata refresh (whether or not fresh metadata is obtained), if requireValidMetadata is true, and there is a validUntil XML attribute on the document root element, and the difference between validUntil and the current time is less than expirationWarningThreshold, the system logs a warning about the impending expiration. + +tooltip.filter-name=Filter Name +tooltip.enable-filter=Enable Filter? +tooltip.enable-service=Enable Service? diff --git a/backend/src/main/resources/i18n/messages_es.properties b/backend/src/main/resources/i18n/messages_es.properties index f90cad6a4..449cd3af0 100644 --- a/backend/src/main/resources/i18n/messages_es.properties +++ b/backend/src/main/resources/i18n/messages_es.properties @@ -8,7 +8,7 @@ action.clear=(es) Clear action.delete=(es) Delete action.remove=(es) Remove action.save=(es) Save -action.toggle=(es) Toggle { label } +action.toggle=(es) Toggle action.add-contact=(es) Add Contact action.add-contacts=(es) Add Contacts action.use-mine=(es) Use My Changes @@ -31,6 +31,12 @@ action.choose-file=(es) Choose File action.search-by=(es) Search By action.preview=(es) Preview action.select-metadata-filter-type=(es) Select a metadata filter type +action.add-authentication-method=(es) Add Authentication Method +action.move-up=(es) Move Up +action.move-down=(es) Move Down +action.edit=(es) Edit +action.add-filter=(es) Add Filter +action.manage-filters=(es) Manage Filters value.enabled=(es) Enabled value.disabled=(es) Disabled @@ -39,6 +45,9 @@ value.file=(es) File value.memory=(es) Memory value.true=(es) True value.false=(es) False +value.regex=(es) Regex +value.script=(es) Script +value.entity-id=(es) Entity ID value.file-backed-http-metadata-provider=(es) FileBackedHttpMetadataProvider value.entity-attributes-filter=(es) EntityAttributes Filter @@ -139,7 +148,7 @@ label.contact-name=(es) Contact Name label.select-contact-type=(es) Select Contact Type label.contact-email-address=(es) Contact Email Address label.sign-the-assertion=(es) Sign the Assertion -label.dont-sign-the-response=(es) Don''t Sign the Response +label.dont-sign-the-response=(es) Don\u0027t Sign the Response label.turn-off-encryption-of-response=(es) Turn Off Encryption of Response label.use-sha1-signing-algorithm=(es) Use SHA1 Signing Algorithm label.nameid-format-to-send=(es) NameID Format to Send @@ -201,10 +210,11 @@ label.service-enabled=(es) Service Enabled label.filter-name=(es) Filter Name label.filter-enabled=(es) Filter Enabled label.filter-target=(es) FilterTarget +label.filter-type=(es) Filter Type label.value=(es) Value label.binding-type=(es) Binding Type label.sign-assertion=(es) Sign Assertions -label.dont-sign-response=(es) Don''t Sign Response +label.dont-sign-response=(es) Don\u0027t Sign Response label.turn-off-encryption=(es) Turn off encryption label.use-sha=(es) Use Sha label.ignore-authentication-method=(es) Ignore Authentication Method @@ -223,13 +233,12 @@ label.binding=(es) Binding label.location-url=(es) Location URL label.make-default=(es) Make Default label.metadata-provider-name-dashboard-display-only=(es) Metadata Provider Name (Dashboard Display Only) +label.default-authentication-methods=(es) Default Authentication Method(s) label.filter-name=(es) Filter Name (Dashboard Display Only) label.metadata-filter-name=(es) Metadata Filter Name (Dashboard Display Only) label.filter-enable=(es) Enable this Filter? label.search-criteria=(es) Search Criteria -label.regex=(es) Regex -label.script=(es) Script label.metadata-filter=(es) Metadata Filter label.metadata-filter-type=(es) Metadata Filter Type @@ -270,10 +279,12 @@ label.metadata-url=(es) Metadata URL label.xml-id=(es) ID label.enable-service=(es) Enable this service? label.metadata-provider-type=(es) Metadata Provider Type -label.metadata-provider-name=(es) Metadata Provider Name (Dashboard Display Only) +label.metadata-provider-name=(es) Metadata Provider Name label.select-metadata-type=(es) Select a metadata provider type +label.metadata-provider-status=(es) Metadata Provider Status label.enable-provider-upon-saving=(es) Enable Metadata Provider upon saving? +label.enable-filter=(es) Enable Filter? label.required-valid-until=(es) Required Valid Until Filter label.max-validity-interval=(es) Max Validity Interval label.signature-validation-filter=(es) Signature Validation Filter @@ -284,7 +295,38 @@ label.retained-roles=(es) Retained Roles label.remove-roleless-entity-descriptors=(es) Remove Roleless Entity Descriptors? label.remove-empty-entities-descriptors=(es) Remove Empty Entities Descriptors? +label.select-metadata-provider-type=(es) Select Metadata Provider Type +label.filter-list=(es) Filter List +label.common-attributes=(es) Common Attributes +label.reloading-attributes=(es) Reloading Attributes +label.metadata-filter-plugins=(es) Metadata Filter Plugins +label.advanced-settings=(es) Advanced Settings +label.edit-metadata-provider=(es) Edit Metadata Provider + +label.metadata-ui=(es) User Interface / MDUI Information +label.descriptor-info=(es) SP SSO Descriptor Information +label.key-info=(es) Security Information +label.assertion=(es) Assertion Consumer Service +label.relying-party=(es) Relying Party Overrides +label.org-info=(es) Organization Information + +label.attribute-eduPersonPrincipalName=(es) eduPersonPrincipalName (EPPN) +label.attribute-uid=(es) uid +label.attribute-mail=(es) mail +label.attribute-surname=(es) surname +label.attribute-givenName=(es) givenName +label.attribute-eduPersonAffiliation=(es) eduPersonAffiliation +label.attribute-eduPersonScopedAffiliation=(es) eduPersonScopedAffiliation +label.attribute-eduPersonPrimaryAffiliation=(es) eduPersonPrimaryAffiliation +label.attribute-eduPersonEntitlement=(es) eduPersonEntitlement +label.attribute-eduPersonAssurance=(es) eduPersonAssurance +label.attribute-eduPersonUniqueId=(es) eduPersonUniqueId +label.attribute-employeeNumber=(es) employeeNumber + message.must-be-unique=(es) Must be unique. +message.name-must-be-unique=(es) Name must be unique. +message.uri-valid-format=(es) URI must be valid format. +message.id-unique=(es) ID must be unique. message.conflict=(es) Conflict message.data-version-contention=(es) Data Version Contention @@ -302,14 +344,14 @@ message.delete-filter-body=(es) You are deleting a metadata filter. This cannot message.unsaved-dialog-title=(es) Save your information? message.unsaved-editor=(es) You have not saved your changes. If you exit this screen, your changes will be lost. message.editor-invalid=(es) All forms must be valid before changes can be saved! -message.unsaved-source-1=(es) You have not completed the wizard! Do you wish to save this information? You can finish the wizard later by clicking the ''Edit'' +message.unsaved-source-1=(es) You have not completed the wizard! Do you wish to save this information? You can finish the wizard later by clicking the \u0027Edit\u0027 message.unsaved-source-2=(es) icon on the dashboard. message.service-resolver-name-required=(es) Service Resolver Name is required message.entity-id-required=(es) Entity ID is required message.entity-id-must-be-unique=(es) Entity ID must be unique message.file-upload-alert=(es) Note: You can only import a file with a single entityID (EntityDescriptor element) in it. Anything more in that file will result in an error. message.add-new-md-resolver=(es) Add a new metadata source -message.wizard-status=(es) Step { index } of {{ length }} +message.wizard-status=(es) Step { index } of { length } message.entity-id-min-unique=(es) You must add at least one entity id target and they must each be unique. message.required-for-scripts=(es) Required for Scripts message.required-for-regex=(es) Required for Regex @@ -338,7 +380,7 @@ tooltip.logout-endpoints-binding-type=(es) Logout Endpoints Binding Type tooltip.mdui-display-name=(es) Typically, the IdP Display Name field will be presented on IdP discovery service interfaces. tooltip.mdui-information-url=(es) The IdP Information URL is a link to a comprehensive information page about the IdP. This page should expand on the content of the IdP Description field. tooltip.mdui-description=(es) The IdP Description is a brief description of the IdP service. On a well-designed discovery interface, the IdP Description will be presented to the user in addition to the IdP Display Name, and so the IdP Description helps disambiguate duplicate or similar IdP Display Names. -tooltip.mdui-privacy-statement-url=(es) The IdP Privacy Statement URL is a link to the IdP''s Privacy Statement. The content of the Privacy Statement should be targeted at end users. +tooltip.mdui-privacy-statement-url=(es) The IdP Privacy Statement URL is a link to the IdP\u0027s Privacy Statement. The content of the Privacy Statement should be targeted at end users. tooltip.mdui-logo-url=(es) The IdP Logo URL in metadata points to an image file on a remote server. A discovery service, for example, may rely on a visual cue (i.e., a logo) instead of or in addition to the IdP Display Name. tooltip.mdui-logo-width=(es) The logo should have a minimum width of 100 pixels tooltip.mdui-logo-height=(es) The logo should have a minimum height of 75 pixels and a maximum height of 150 pixels (or the application will scale it proportionally) @@ -346,12 +388,12 @@ tooltip.organization-name=(es) Organization Name tooltip.organization-display-name=(es) Organization Display Name tooltip.organization-url=(es) Organization Url tooltip.contact-name=(es) Contact Name +tooltip.contact-type=(es) Contact Type tooltip.contact-email=(es) Contact Email tooltip.sign-assertion=(es) Sign Assertion -tooltip.dont-sign-response=(es) Don''t Sign Response +tooltip.dont-sign-response=(es) Don\u0027t Sign Response tooltip.turn-off-encryption=(es) Turn Off Encryption of Response tooltip.usa-sha-algorithm=(es) Use SHA1 Signing Algorithm -tooltip.nameid-format=(es) Add NameID Format tooltip.authentication-methods-to-use=(es) Authentication Methods to Use tooltip.ignore-auth-method=(es) Ignore any SP-Requested Authentication Method tooltip.omit-not-before-condition=(es) Omit Not Before Condition @@ -360,8 +402,8 @@ tooltip.instruction=(es) Information icon - press spacebar to read additional in tooltip.attribute-release-table=(es) Attribute release table - select the attributes you want to release (default unchecked) tooltip.metadata-filter-name=(es) Metadata Filter Name tooltip.metadata-filter-type=(es) Metadata Filter Type -tooltip.connection-request-timeout=(es) The maximum amount of time to wait for a connection to be returned from the HTTP client''s connection pool manager. Set to PT0S to disable. This attribute is incompatible with httpClientRef. -tooltip.connection-timout=(es) The maximum amount of time to wait to establish a connection with the remote server. Set to PT0S to disable. This attribute is incompatible with httpClientRef. +tooltip.connection-request-timeout=(es) The maximum amount of time to wait for a connection to be returned from the HTTP client\u0027s connection pool manager. Set to PT0S to disable. This attribute is incompatible with httpClientRef. +tooltip.connection-timeout=(es) The maximum amount of time to wait to establish a connection with the remote server. Set to PT0S to disable. This attribute is incompatible with httpClientRef. tooltip.socket-timeout=(es) The maximum amount of time to wait between two consecutive packets while reading from the socket connected to the remote server. Set to PT0S to disable. This attribute is incompatible with httpClientRef. tooltip.disregard-tls-cert=(es) If true, no TLS certificate checking will take place over an HTTPS connection. This attribute is incompatible with httpClientRef. (Be careful with this setting, it is typically only used during testing. See the HttpClientConfiguration topic for more information.) tooltip.proxy-host=(es) The hostname of the HTTP proxy through which connections will be made. This attribute is incompatible with httpClientRef. @@ -393,8 +435,12 @@ tooltip.retained-roles=(es) Retained Roles tooltip.remove-roleless-entity-descriptors=(es) Controls whether to keep entity descriptors that contain no roles. tooltip.remove-empty-entities-descriptors=(es) Controls whether to keep entities descriptors that contain no entity descriptors. -tooltip.min-refresh-delay=(es) Lower bound on the next refresh from the time calculated based on the metadata''s expiration. -tooltip.max-refresh-delay=(es) Upper bound on the next refresh from the time calculated based on the metadata''s expiration. -tooltip.refresh-delay-factor=(es) A factor applied to the initially determined refresh time in order to determine the next refresh time (typically to ensure refresh takes place prior to the metadata''s expiration). Attempts to refresh metadata will generally begin around the product of this number and the maximum refresh delay. +tooltip.min-refresh-delay=(es) Lower bound on the next refresh from the time calculated based on the metadata\u0027s expiration. +tooltip.max-refresh-delay=(es) Upper bound on the next refresh from the time calculated based on the metadata\u0027s expiration. +tooltip.refresh-delay-factor=(es) A factor applied to the initially determined refresh time in order to determine the next refresh time (typically to ensure refresh takes place prior to the metadata\u0027s expiration). Attempts to refresh metadata will generally begin around the product of this number and the maximum refresh delay. tooltip.resolve-via-predicates-only=(es) Flag indicating whether resolution may be performed solely by applying predicates to the entire metadata collection, when an entityID input criterion is not supplied. tooltip.expiration-warning-threshold=(es) For each attempted metadata refresh (whether or not fresh metadata is obtained), if requireValidMetadata is true, and there is a validUntil XML attribute on the document root element, and the difference between validUntil and the current time is less than expirationWarningThreshold, the system logs a warning about the impending expiration. + +tooltip.filter-name=(es) Filter Name +tooltip.enable-filter=(es) Enable Filter? +tooltip.enable-service=(es) Enable Service? diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy index 0c7fe9abf..cecaa25e6 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy @@ -475,6 +475,8 @@ class TestObjectGenerator { it.metadataURL = 'https://idp.unicon.net/idp/shibboleth' it.reloadableMetadataResolverAttributes = new ReloadableMetadataResolverAttributes().with { + it.minRefreshDelay = 'PT0M' + it.maxRefreshDelay = 'P1D' it } it diff --git a/backend/src/test/resources/conf/278.2.xml b/backend/src/test/resources/conf/278.2.xml index ad3cb6c44..34bf7ae16 100644 --- a/backend/src/test/resources/conf/278.2.xml +++ b/backend/src/test/resources/conf/278.2.xml @@ -39,8 +39,9 @@ - + metadataURL="https://idp.unicon.net/idp/shibboleth" + minRefreshDelay='PT0M' + maxRefreshDelay='P1D'> diff --git a/backend/src/test/resources/conf/278.xml b/backend/src/test/resources/conf/278.xml index cb5317531..e47fbd838 100644 --- a/backend/src/test/resources/conf/278.xml +++ b/backend/src/test/resources/conf/278.xml @@ -32,7 +32,9 @@ + metadataURL="https://idp.unicon.net/idp/shibboleth" + minRefreshDelay='PT0M' + maxRefreshDelay='P1D'> diff --git a/backend/src/test/resources/conf/532.xml b/backend/src/test/resources/conf/532.xml index b2be43498..3052217a9 100644 --- a/backend/src/test/resources/conf/532.xml +++ b/backend/src/test/resources/conf/532.xml @@ -8,6 +8,7 @@ - + metadataURL="https://idp.unicon.net/idp/shibboleth" + minRefreshDelay='PT0M' + maxRefreshDelay='P1D' /> diff --git a/run-app-es.sh b/run-app-es.sh deleted file mode 100755 index 99c47d1a1..000000000 --- a/run-app-es.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -./gradlew -Dshibui.logout-url=/dashboard clean bootRun npm_run_start --parallel -Pnpm-args="-- --i18nFile=./src/locale/es.xlf --i18nFormat=xlf --locale=es --aot" \ No newline at end of file diff --git a/ui/package.json b/ui/package.json index 7865053ba..d89f39898 100644 --- a/ui/package.json +++ b/ui/package.json @@ -5,9 +5,6 @@ "scripts": { "ng": "ng", "start": "ng serve --proxy-config proxy.conf.json", - "start:en": "ng serve --proxy-config proxy.conf.json --i18nFile=./src/locale/en.xlf --i18nFormat=xlf --locale=en --aot", - "start:es": "ng serve --proxy-config proxy.conf.json --i18nFile=./src/locale/es.xlf --i18nFormat=xlf --locale=es --aot", - "start:prod": "ng serve --proxy-config proxy.conf.json --i18nFile=./src/locale/en.xlf --i18nFormat=xlf --locale=en --aot --environment=prod", "build": "ng build", "test": "ng test --code-coverage", "lint": "ng lint", diff --git a/ui/src/app/app.module.ts b/ui/src/app/app.module.ts index 4448e7f37..6d54d350a 100644 --- a/ui/src/app/app.module.ts +++ b/ui/src/app/app.module.ts @@ -1,5 +1,5 @@ import { BrowserModule } from '@angular/platform-browser'; -import { NgModule, LOCALE_ID } from '@angular/core'; +import { NgModule } from '@angular/core'; import { StoreModule } from '@ngrx/store'; import { EffectsModule } from '@ngrx/effects'; import { StoreDevtoolsModule } from '@ngrx/store-devtools'; @@ -58,7 +58,6 @@ import { I18nModule } from './i18n/i18n.module'; AppRoutingModule ], providers: [ - { provide: LOCALE_ID, useValue: getCurrentLocale(null) }, NavigatorService, { provide: RouterStateSerializer, useClass: CustomRouterStateSerializer }, { diff --git a/ui/src/app/i18n/component/translate.component.ts b/ui/src/app/i18n/component/translate.component.ts index 42bf18407..9eb6f6623 100644 --- a/ui/src/app/i18n/component/translate.component.ts +++ b/ui/src/app/i18n/component/translate.component.ts @@ -37,7 +37,6 @@ export class TranslateComponent implements OnDestroy { @Input() set params(params: any) { this.currentParams = params || {}; - console.log(params); this.update(); } diff --git a/ui/src/app/metadata/domain/component/forms/assertion-form.component.html b/ui/src/app/metadata/domain/component/forms/assertion-form.component.html index 709c70bd4..7433c7711 100644 --- a/ui/src/app/metadata/domain/component/forms/assertion-form.component.html +++ b/ui/src/app/metadata/domain/component/forms/assertion-form.component.html @@ -2,7 +2,7 @@

- Assertion Consumer Service Endpoints: + Assertion Consumer Service Endpoints:    - Add NameID Format Popover + + Add NameID Format Popover + diff --git a/ui/src/app/metadata/domain/component/forms/descriptor-info-form.component.spec.ts b/ui/src/app/metadata/domain/component/forms/descriptor-info-form.component.spec.ts index 7527f5e3c..d902432fd 100644 --- a/ui/src/app/metadata/domain/component/forms/descriptor-info-form.component.spec.ts +++ b/ui/src/app/metadata/domain/component/forms/descriptor-info-form.component.spec.ts @@ -11,6 +11,7 @@ import { DescriptorInfoFormComponent } from './descriptor-info-form.component'; import * as stubs from '../../../../../testing/resolver.stub'; import { SharedModule } from '../../../../shared/shared.module'; import { MockI18nModule } from '../../../../../testing/i18n.stub'; +import { MockListValueService } from '../../../../../testing/list-values.stub'; @Component({ template: `` @@ -48,7 +49,7 @@ describe('Descriptor Info Form Component', () => { ProviderValueEmitter, ProviderStatusEmitter, NgbPopoverConfig, - ListValuesService + { provide: ListValuesService, useClass: MockListValueService } ], imports: [ NoopAnimationsModule, diff --git a/ui/src/app/metadata/domain/component/forms/finish-form.component.html b/ui/src/app/metadata/domain/component/forms/finish-form.component.html index 5d9682b8b..e5fef1c32 100644 --- a/ui/src/app/metadata/domain/component/forms/finish-form.component.html +++ b/ui/src/app/metadata/domain/component/forms/finish-form.component.html @@ -9,10 +9,11 @@ translate="label.enable-this-service-opon-saving" for="serviceEnabled">Enable this service upon saving?

- Enable this service upon saving popover + + Enable this service upon saving popover + diff --git a/ui/src/app/metadata/domain/component/forms/finish-form.component.spec.ts b/ui/src/app/metadata/domain/component/forms/finish-form.component.spec.ts index 0d3ea08a4..882590b2b 100644 --- a/ui/src/app/metadata/domain/component/forms/finish-form.component.spec.ts +++ b/ui/src/app/metadata/domain/component/forms/finish-form.component.spec.ts @@ -14,6 +14,7 @@ import * as stubs from '../../../../../testing/resolver.stub'; import { FileBackedHttpMetadataResolver } from '../../entity'; import { InputDefaultsDirective } from '../../../../shared/directive/input-defaults.directive'; import { MockI18nModule } from '../../../../../testing/i18n.stub'; +import { MockListValueService } from '../../../../../testing/list-values.stub'; @Component({ template: `` @@ -42,7 +43,7 @@ describe('Finished Form Component', () => { ProviderValueEmitter, ProviderStatusEmitter, NgbPopoverConfig, - ListValuesService, + { provide: ListValuesService, useClass: MockListValueService }, { provide: Router, useClass: RouterStub }, { provide: ActivatedRoute, useClass: ActivatedRouteStub } ], diff --git a/ui/src/app/metadata/domain/component/forms/key-info-form.component.html b/ui/src/app/metadata/domain/component/forms/key-info-form.component.html index 0da342a5f..e4a9ea4d7 100644 --- a/ui/src/app/metadata/domain/component/forms/key-info-form.component.html +++ b/ui/src/app/metadata/domain/component/forms/key-info-form.component.html @@ -91,7 +91,7 @@

- X509 Certificates: + X509 Certificates:   

diff --git a/ui/src/app/metadata/domain/component/forms/key-info-form.component.spec.ts b/ui/src/app/metadata/domain/component/forms/key-info-form.component.spec.ts index fd6ccd5db..0b6751cc3 100644 --- a/ui/src/app/metadata/domain/component/forms/key-info-form.component.spec.ts +++ b/ui/src/app/metadata/domain/component/forms/key-info-form.component.spec.ts @@ -11,6 +11,7 @@ import * as stubs from '../../../../../testing/resolver.stub'; import { FileBackedHttpMetadataResolver } from '../../entity'; import { InputDefaultsDirective } from '../../../../shared/directive/input-defaults.directive'; import { MockI18nModule } from '../../../../../testing/i18n.stub'; +import { MockListValueService } from '../../../../../testing/list-values.stub'; @Component({ template: `` @@ -43,7 +44,7 @@ describe('Security (Key) Info Form Component', () => { ProviderValueEmitter, ProviderStatusEmitter, NgbPopoverConfig, - ListValuesService + { provide: ListValuesService, useClass: MockListValueService } ], imports: [ NoopAnimationsModule, diff --git a/ui/src/app/metadata/domain/component/forms/logout-form.component.html b/ui/src/app/metadata/domain/component/forms/logout-form.component.html index 38c0ac0a3..c8a73f3e6 100644 --- a/ui/src/app/metadata/domain/component/forms/logout-form.component.html +++ b/ui/src/app/metadata/domain/component/forms/logout-form.component.html @@ -2,7 +2,7 @@

- Logout Endpoints: + Logout Endpoints:  

diff --git a/ui/src/app/metadata/domain/component/forms/logout-form.component.spec.ts b/ui/src/app/metadata/domain/component/forms/logout-form.component.spec.ts index 83f1fafe4..89d8b9b09 100644 --- a/ui/src/app/metadata/domain/component/forms/logout-form.component.spec.ts +++ b/ui/src/app/metadata/domain/component/forms/logout-form.component.spec.ts @@ -12,6 +12,7 @@ import * as stubs from '../../../../../testing/resolver.stub'; import { FileBackedHttpMetadataResolver } from '../../entity'; import { InputDefaultsDirective } from '../../../../shared/directive/input-defaults.directive'; import { MockI18nModule } from '../../../../../testing/i18n.stub'; +import { MockListValueService } from '../../../../../testing/list-values.stub'; @Component({ template: `` @@ -41,7 +42,7 @@ describe('Logout Endpoints Form Component', () => { ProviderValueEmitter, ProviderStatusEmitter, NgbPopoverConfig, - ListValuesService + { provide: ListValuesService, useClass: MockListValueService } ], imports: [ NoopAnimationsModule, diff --git a/ui/src/app/metadata/domain/component/forms/metadata-ui-form.component.spec.ts b/ui/src/app/metadata/domain/component/forms/metadata-ui-form.component.spec.ts index b74dc94db..3c86d3b13 100644 --- a/ui/src/app/metadata/domain/component/forms/metadata-ui-form.component.spec.ts +++ b/ui/src/app/metadata/domain/component/forms/metadata-ui-form.component.spec.ts @@ -11,6 +11,7 @@ import * as stubs from '../../../../../testing/resolver.stub'; import { FileBackedHttpMetadataResolver } from '../../entity'; import { InputDefaultsDirective } from '../../../../shared/directive/input-defaults.directive'; import { MockI18nModule } from '../../../../../testing/i18n.stub'; +import { MockListValueService } from '../../../../../testing/list-values.stub'; @Component({ template: `` @@ -39,7 +40,7 @@ describe('Metadata UI Form Component', () => { ProviderValueEmitter, ProviderStatusEmitter, NgbPopoverConfig, - ListValuesService + { provide: ListValuesService, useClass: MockListValueService } ], imports: [ NoopAnimationsModule, diff --git a/ui/src/app/metadata/domain/component/forms/organization-info-form.component.spec.ts b/ui/src/app/metadata/domain/component/forms/organization-info-form.component.spec.ts index 57708fbad..e5a4d30e4 100644 --- a/ui/src/app/metadata/domain/component/forms/organization-info-form.component.spec.ts +++ b/ui/src/app/metadata/domain/component/forms/organization-info-form.component.spec.ts @@ -7,6 +7,7 @@ import { ListValuesService } from '../../../domain/service/list-values.service'; import { OrganizationInfoFormComponent } from './organization-info-form.component'; import * as stubs from '../../../../../testing/resolver.stub'; import { MockI18nModule } from '../../../../../testing/i18n.stub'; +import { MockListValueService } from '../../../../../testing/list-values.stub'; describe('Organization Info Form Component', () => { let fixture: ComponentFixture; @@ -18,7 +19,7 @@ describe('Organization Info Form Component', () => { ProviderValueEmitter, ProviderStatusEmitter, NgbPopoverConfig, - ListValuesService + { provide: ListValuesService, useClass: MockListValueService } ], imports: [ NoopAnimationsModule, diff --git a/ui/src/app/metadata/domain/component/forms/relying-party-form.component.html b/ui/src/app/metadata/domain/component/forms/relying-party-form.component.html index 996bc5ae7..4fb9f2713 100644 --- a/ui/src/app/metadata/domain/component/forms/relying-party-form.component.html +++ b/ui/src/app/metadata/domain/component/forms/relying-party-form.component.html @@ -100,7 +100,7 @@ Authentication Methods to Use   - diff --git a/ui/src/app/metadata/domain/component/forms/relying-party-form.component.spec.ts b/ui/src/app/metadata/domain/component/forms/relying-party-form.component.spec.ts index 0849591c6..274bbc3e0 100644 --- a/ui/src/app/metadata/domain/component/forms/relying-party-form.component.spec.ts +++ b/ui/src/app/metadata/domain/component/forms/relying-party-form.component.spec.ts @@ -10,6 +10,7 @@ import * as stubs from '../../../../../testing/resolver.stub'; import { SharedModule } from '../../../../shared/shared.module'; import { FileBackedHttpMetadataResolver } from '../../entity'; import { MockI18nModule } from '../../../../../testing/i18n.stub'; +import { MockListValueService } from '../../../../../testing/list-values.stub'; @Component({ @@ -48,7 +49,7 @@ describe('Relying Party Form Component', () => { ProviderValueEmitter, ProviderStatusEmitter, NgbPopoverConfig, - ListValuesService + { provide: ListValuesService, useClass: MockListValueService } ], imports: [ NoopAnimationsModule, diff --git a/ui/src/app/metadata/domain/domain.module.ts b/ui/src/app/metadata/domain/domain.module.ts index 5cf2a72b0..a9120f45d 100644 --- a/ui/src/app/metadata/domain/domain.module.ts +++ b/ui/src/app/metadata/domain/domain.module.ts @@ -13,6 +13,7 @@ import { MetadataProviderService } from './service/provider.service'; import { EntityEffects } from './effect/entity.effect'; import { PreviewDialogComponent } from './component/preview-dialog.component'; import { MetadataFilterService } from './service/filter.service'; +import { AttributesService } from './service/attributes.service'; import { I18nModule } from '../../i18n/i18n.module'; export const COMPONENTS = [ @@ -46,7 +47,8 @@ export class DomainModule { ProviderStatusEmitter, ProviderValueEmitter, MetadataProviderService, - MetadataFilterService + MetadataFilterService, + AttributesService ] }; } diff --git a/ui/src/app/metadata/domain/model/properties/release-attribute.ts b/ui/src/app/metadata/domain/model/properties/release-attribute.ts new file mode 100644 index 000000000..7edc37b6a --- /dev/null +++ b/ui/src/app/metadata/domain/model/properties/release-attribute.ts @@ -0,0 +1,4 @@ +export interface ReleaseAttribute { + key: string; + label: string; +} diff --git a/ui/src/app/metadata/domain/service/attributes.service.spec.ts b/ui/src/app/metadata/domain/service/attributes.service.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/ui/src/app/metadata/domain/service/attributes.service.ts b/ui/src/app/metadata/domain/service/attributes.service.ts new file mode 100644 index 000000000..c6b671e01 --- /dev/null +++ b/ui/src/app/metadata/domain/service/attributes.service.ts @@ -0,0 +1,38 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable, throwError } from 'rxjs'; +import { catchError, shareReplay, map } from 'rxjs/operators'; +import { ReleaseAttribute } from '../model/properties/release-attribute'; + +const CACHE_SIZE = 1; + +@Injectable() +export class AttributesService { + + readonly endpoint = '/customAttributes'; + readonly base = '/api'; + + private cache$: Observable; + + constructor( + private http: HttpClient + ) { } + + query(path: string = this.endpoint): Observable { + if (!this.cache$) { + this.cache$ = this.requestAttributes(path).pipe( + shareReplay(CACHE_SIZE) + ); + } + + return this.cache$; + } + + requestAttributes(path: string): Observable { + return this.http.get(`${this.base}${path}`, {}) + .pipe( + map(attrs => attrs.map((attr: any) => ({ key: attr.name, label: attr.displayName }))), + catchError(err => throwError([])) + ); + } +} diff --git a/ui/src/app/metadata/domain/service/list-values.service.spec.ts b/ui/src/app/metadata/domain/service/list-values.service.spec.ts index e90c51a76..2c26ba912 100644 --- a/ui/src/app/metadata/domain/service/list-values.service.spec.ts +++ b/ui/src/app/metadata/domain/service/list-values.service.spec.ts @@ -2,6 +2,8 @@ import { TestBed, async, inject } from '@angular/core/testing'; import { EntityValidators } from './entity-validators.service'; import { Observable, of } from 'rxjs'; import { ListValuesService } from './list-values.service'; +import { AttributesService } from './attributes.service'; +import { MockAttributeService } from '../../../../testing/attributes.stub'; describe(`ListValuesService`, () => { let service: ListValuesService; @@ -9,6 +11,7 @@ describe(`ListValuesService`, () => { TestBed.configureTestingModule({ imports: [], providers: [ + { provide: AttributesService, useClass: MockAttributeService }, ListValuesService ] }); diff --git a/ui/src/app/metadata/domain/service/list-values.service.ts b/ui/src/app/metadata/domain/service/list-values.service.ts index 644a2be7b..dff88ea7e 100644 --- a/ui/src/app/metadata/domain/service/list-values.service.ts +++ b/ui/src/app/metadata/domain/service/list-values.service.ts @@ -2,10 +2,14 @@ import { Injectable } from '@angular/core'; import { Observable, of } from 'rxjs'; import { debounceTime, distinctUntilChanged, combineLatest } from 'rxjs/operators'; +import { AttributesService } from './attributes.service'; +import { ReleaseAttribute } from '../model/properties/release-attribute'; @Injectable() export class ListValuesService { - constructor() {} + constructor( + private attributes: AttributesService + ) {} readonly nameIdFormats: Observable = of([ 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified', @@ -20,21 +24,9 @@ export class ListValuesService { 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport' ]); - readonly attributesToRelease: Observable<{ key: string, label: string }[]> = of([ - { key: 'eduPersonPrincipalName', label: 'eduPersonPrincipalName (EPPN)' }, - { key: 'uid', label: 'uid' }, - { key: 'mail', label: 'mail' }, - { key: 'surname', label: 'surname' }, - { key: 'givenName', label: 'givenName' }, - { key: 'displayName', label: 'displayName' }, - { key: 'eduPersonAffiliation', label: 'eduPersonAffiliation' }, - { key: 'eduPersonScopedAffiliation', label: 'eduPersonScopedAffiliation' }, - { key: 'eduPersonPrimaryAffiliation', label: 'eduPersonPrimaryAffiliation' }, - { key: 'eduPersonEntitlement', label: 'eduPersonEntitlement' }, - { key: 'eduPersonAssurance', label: 'eduPersonAssurance' }, - { key: 'eduPersonUniqueId', label: 'eduPersonUniqueId' }, - { key: 'employeeNumber', label: 'employeeNumber' } - ]); + get attributesToRelease(): Observable { + return this.attributes.query(); + } searchStringList = (list: Observable): Function => (text$: Observable) => diff --git a/ui/src/app/metadata/manager/component/provider-item.component.html b/ui/src/app/metadata/manager/component/provider-item.component.html index 0b222543d..f55293a4e 100644 --- a/ui/src/app/metadata/manager/component/provider-item.component.html +++ b/ui/src/app/metadata/manager/component/provider-item.component.html @@ -38,8 +38,8 @@
@@ -42,7 +43,7 @@ [routerLink]="['../', 'edit', route.path]" role="button" [attr.aria-label]="route.label"> - + @@ -54,9 +55,9 @@ - + diff --git a/ui/src/app/metadata/provider/container/provider-filter-list.component.html b/ui/src/app/metadata/provider/container/provider-filter-list.component.html index 2e13ae19f..d353bf449 100644 --- a/ui/src/app/metadata/provider/container/provider-filter-list.component.html +++ b/ui/src/app/metadata/provider/container/provider-filter-list.component.html @@ -4,7 +4,8 @@
- Edit Metadata Provider - {{ (provider$ | async).name }} + Edit Metadata Provider - {{ (provider$ | async).name }} +
@@ -19,7 +20,7 @@ - Add Filter + Add Filter
@@ -36,11 +37,11 @@ - Filter Name - Filter Type - Enabled? - Edit - Delete + Filter Name + Filter Type + Enabled? + Edit + Delete @@ -48,11 +49,11 @@ {{ i + 1 }} @@ -65,8 +66,8 @@ 'fa-check-square text-success': filter.filterEnabled, 'fa-square-o text-dark': !filter.filterEnabled }"> - Enable - Disable + Enable + Disable @@ -75,13 +76,13 @@ [class.disabled]="isSaving$ | async" [routerLink]="['../', 'filter', filter.resourceId, 'edit']"> - Edit + Edit diff --git a/ui/src/app/metadata/provider/model/base.provider.form.ts b/ui/src/app/metadata/provider/model/base.provider.form.ts index 7c78fe332..33ff3aa3a 100644 --- a/ui/src/app/metadata/provider/model/base.provider.form.ts +++ b/ui/src/app/metadata/provider/model/base.provider.form.ts @@ -26,7 +26,7 @@ export const BaseMetadataProviderEditor: Wizard = { const err = namesList.indexOf(value) > -1 ? { code: 'INVALID_NAME', path: `#${property.path}`, - message: 'Name must be unique.', + message: 'message.name-must-be-unique', params: [value] } : null; return err; @@ -35,7 +35,7 @@ export const BaseMetadataProviderEditor: Wizard = { return !UriValidator.isUri(value) ? { code: 'INVALID_URI', path: `#${property.path}`, - message: 'URI must be valid format.', + message: 'message.uri-valid-format', params: [value] } : null; } diff --git a/ui/src/app/metadata/provider/model/file-backed-http.provider.form.ts b/ui/src/app/metadata/provider/model/file-backed-http.provider.form.ts index 17238df3b..987a0effa 100644 --- a/ui/src/app/metadata/provider/model/file-backed-http.provider.form.ts +++ b/ui/src/app/metadata/provider/model/file-backed-http.provider.form.ts @@ -12,7 +12,7 @@ export const FileBackedHttpMetadataProviderWizard: Wizard -1 ? { code: 'INVALID_ID', path: `#${property.path}`, - message: 'ID must be unique.', + message: 'message.id-unique', params: [value] } : null; return err; @@ -22,21 +22,21 @@ export const FileBackedHttpMetadataProviderWizard: Wizard = { steps: [ { id: 'new', - label: 'Select Metadata Provider Type', + label: 'label.select-metadata-provider-type', index: 1, initialValues: [], schema: 'assets/schema/provider/metadata-provider.schema.json' diff --git a/ui/src/app/metadata/resolver/component/wizard-nav.component.html b/ui/src/app/metadata/resolver/component/wizard-nav.component.html index b17dbbd0e..34d85715b 100644 --- a/ui/src/app/metadata/resolver/component/wizard-nav.component.html +++ b/ui/src/app/metadata/resolver/component/wizard-nav.component.html @@ -1,32 +1,32 @@