PageRenderTime 42ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/support/cas-server-support-saml-idp-core/src/main/java/org/apereo/cas/support/saml/services/idp/metadata/SamlRegisteredServiceServiceProviderMetadataFacade.java

https://github.com/frett/cas
Java | 283 lines | 166 code | 38 blank | 79 comment | 12 complexity | 21831aa792953a23089c195f8cb157d2 MD5 | raw file
  1. package org.apereo.cas.support.saml.services.idp.metadata;
  2. import org.apereo.cas.support.saml.SamlIdPUtils;
  3. import org.apereo.cas.support.saml.services.SamlRegisteredService;
  4. import org.apereo.cas.support.saml.services.idp.metadata.cache.SamlRegisteredServiceCachingMetadataResolver;
  5. import org.apereo.cas.util.DateTimeUtils;
  6. import lombok.Getter;
  7. import lombok.RequiredArgsConstructor;
  8. import lombok.SneakyThrows;
  9. import lombok.extern.slf4j.Slf4j;
  10. import lombok.val;
  11. import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
  12. import org.apache.commons.lang3.ObjectUtils;
  13. import org.opensaml.core.criterion.EntityIdCriterion;
  14. import org.opensaml.saml.common.xml.SAMLConstants;
  15. import org.opensaml.saml.metadata.resolver.MetadataResolver;
  16. import org.opensaml.saml.saml2.core.RequestAbstractType;
  17. import org.opensaml.saml.saml2.metadata.AssertionConsumerService;
  18. import org.opensaml.saml.saml2.metadata.ContactPerson;
  19. import org.opensaml.saml.saml2.metadata.EntityDescriptor;
  20. import org.opensaml.saml.saml2.metadata.Extensions;
  21. import org.opensaml.saml.saml2.metadata.KeyDescriptor;
  22. import org.opensaml.saml.saml2.metadata.NameIDFormat;
  23. import org.opensaml.saml.saml2.metadata.Organization;
  24. import org.opensaml.saml.saml2.metadata.SPSSODescriptor;
  25. import org.opensaml.saml.saml2.metadata.SingleLogoutService;
  26. import org.opensaml.xmlsec.signature.Signature;
  27. import java.time.ZonedDateTime;
  28. import java.util.ArrayList;
  29. import java.util.List;
  30. import java.util.Optional;
  31. import java.util.stream.Collectors;
  32. /**
  33. * This is {@link SamlRegisteredServiceServiceProviderMetadataFacade} that acts a façade between the SAML metadata resolved
  34. * from a metadata resource and other outer layers in CAS that need access to the bits of that
  35. * metadata. Once the metadata resolved for a service is adapted and parsed for a given entity id,
  36. * callers will be able to peek into the various configuration elements of the metadata to handle
  37. * further saml processing. A metadata adaptor is always linked to a saml service.
  38. *
  39. * @author Misagh Moayyed
  40. * @since 5.0.0
  41. */
  42. @Slf4j
  43. @RequiredArgsConstructor
  44. @Getter
  45. public class SamlRegisteredServiceServiceProviderMetadataFacade {
  46. private final SPSSODescriptor ssoDescriptor;
  47. private final EntityDescriptor entityDescriptor;
  48. private final MetadataResolver metadataResolver;
  49. /**
  50. * Adapt saml metadata and parse. Acts as a facade.
  51. *
  52. * @param resolver the resolver
  53. * @param registeredService the service
  54. * @param entityID the entity id
  55. * @return the saml metadata adaptor
  56. */
  57. public static Optional<SamlRegisteredServiceServiceProviderMetadataFacade> get(final SamlRegisteredServiceCachingMetadataResolver resolver,
  58. final SamlRegisteredService registeredService,
  59. final String entityID) {
  60. return get(resolver, registeredService, entityID, new CriteriaSet());
  61. }
  62. /**
  63. * Adapt saml metadata and parse. Acts as a facade.
  64. *
  65. * @param resolver the resolver
  66. * @param registeredService the service
  67. * @param request the request
  68. * @return the saml metadata adaptor
  69. */
  70. public static Optional<SamlRegisteredServiceServiceProviderMetadataFacade> get(final SamlRegisteredServiceCachingMetadataResolver resolver,
  71. final SamlRegisteredService registeredService,
  72. final RequestAbstractType request) {
  73. return get(resolver, registeredService, SamlIdPUtils.getIssuerFromSamlObject(request));
  74. }
  75. @SneakyThrows
  76. private static Optional<SamlRegisteredServiceServiceProviderMetadataFacade> get(final SamlRegisteredServiceCachingMetadataResolver resolver,
  77. final SamlRegisteredService registeredService,
  78. final String entityID, final CriteriaSet criterions) {
  79. LOGGER.debug("Adapting SAML metadata for CAS service [{}] issued by [{}]", registeredService.getName(), entityID);
  80. criterions.add(new EntityIdCriterion(entityID), true);
  81. LOGGER.debug("Locating metadata for entityID [{}] by attempting to run through the metadata chain...", entityID);
  82. val chainingMetadataResolver = resolver.resolve(registeredService);
  83. LOGGER.info("Resolved metadata chain for service [{}]. Filtering the chain by entity ID [{}]",
  84. registeredService.getServiceId(), entityID);
  85. val entityDescriptor = chainingMetadataResolver.resolveSingle(criterions);
  86. if (entityDescriptor == null) {
  87. LOGGER.warn("Cannot find entity [{}] in metadata provider Ensure the metadata is valid and has not expired.", entityID);
  88. return Optional.empty();
  89. }
  90. LOGGER.debug("Located entity descriptor in metadata for [{}]", entityID);
  91. if (entityDescriptor.getValidUntil() != null && entityDescriptor.getValidUntil().isBeforeNow()) {
  92. LOGGER.warn("Entity descriptor in the metadata has expired at [{}]", entityDescriptor.getValidUntil());
  93. return Optional.empty();
  94. }
  95. return getServiceProviderSsoDescriptor(entityID, chainingMetadataResolver, entityDescriptor);
  96. }
  97. private static Optional<SamlRegisteredServiceServiceProviderMetadataFacade> getServiceProviderSsoDescriptor(final String entityID,
  98. final MetadataResolver chainingMetadataResolver,
  99. final EntityDescriptor entityDescriptor) {
  100. val ssoDescriptor = entityDescriptor.getSPSSODescriptor(SAMLConstants.SAML20P_NS);
  101. if (ssoDescriptor != null) {
  102. LOGGER.debug("Located SP SSODescriptor in metadata for [{}]. Metadata is valid until [{}]", entityID,
  103. ObjectUtils.defaultIfNull(ssoDescriptor.getValidUntil(), "forever"));
  104. if (ssoDescriptor.getValidUntil() != null && ssoDescriptor.getValidUntil().isBeforeNow()) {
  105. LOGGER.warn("SP SSODescriptor in the metadata has expired at [{}]", ssoDescriptor.getValidUntil());
  106. return Optional.empty();
  107. }
  108. return Optional.of(new SamlRegisteredServiceServiceProviderMetadataFacade(ssoDescriptor, entityDescriptor,
  109. chainingMetadataResolver));
  110. }
  111. LOGGER.warn("Could not locate SP SSODescriptor in the metadata for [{}]", entityID);
  112. return Optional.empty();
  113. }
  114. public ZonedDateTime getValidUntil() {
  115. return DateTimeUtils.zonedDateTimeOf(this.ssoDescriptor.getValidUntil());
  116. }
  117. public Organization getOrganization() {
  118. return this.ssoDescriptor.getOrganization();
  119. }
  120. public Signature getSignature() {
  121. return this.ssoDescriptor.getSignature();
  122. }
  123. public List<ContactPerson> getContactPersons() {
  124. return this.ssoDescriptor.getContactPersons();
  125. }
  126. public long getCacheDuration() {
  127. return this.ssoDescriptor.getCacheDuration();
  128. }
  129. public List<KeyDescriptor> getKeyDescriptors() {
  130. return this.ssoDescriptor.getKeyDescriptors();
  131. }
  132. public Extensions getExtensions() {
  133. return this.ssoDescriptor.getExtensions();
  134. }
  135. public List<String> getSupportedProtocols() {
  136. return this.ssoDescriptor.getSupportedProtocols();
  137. }
  138. public boolean isWantAssertionsSigned() {
  139. return this.ssoDescriptor.getWantAssertionsSigned();
  140. }
  141. public boolean isAuthnRequestsSigned() {
  142. return this.ssoDescriptor.isAuthnRequestsSigned();
  143. }
  144. /**
  145. * Is supported protocol?
  146. *
  147. * @param protocol the protocol
  148. * @return true/false
  149. */
  150. public boolean isSupportedProtocol(final String protocol) {
  151. return this.ssoDescriptor.isSupportedProtocol(protocol);
  152. }
  153. /**
  154. * Gets entity id.
  155. *
  156. * @return the entity id
  157. */
  158. public String getEntityId() {
  159. return this.entityDescriptor.getEntityID();
  160. }
  161. /**
  162. * Gets supported name formats.
  163. *
  164. * @return the supported name formats
  165. */
  166. public List<String> getSupportedNameIdFormats() {
  167. val nameIdFormats = new ArrayList<String>();
  168. val children = this.ssoDescriptor.getOrderedChildren();
  169. if (children != null) {
  170. nameIdFormats.addAll(children.stream().filter(NameIDFormat.class::isInstance)
  171. .map(child -> ((NameIDFormat) child).getFormat()).collect(Collectors.toList()));
  172. }
  173. return nameIdFormats;
  174. }
  175. private List<AssertionConsumerService> getAssertionConsumerServices() {
  176. return (List) this.ssoDescriptor.getEndpoints(AssertionConsumerService.DEFAULT_ELEMENT_NAME);
  177. }
  178. public List<SingleLogoutService> getSingleLogoutServices() {
  179. return (List) this.ssoDescriptor.getEndpoints(SingleLogoutService.DEFAULT_ELEMENT_NAME);
  180. }
  181. public SingleLogoutService getSingleLogoutService() {
  182. return getSingleLogoutServices().get(0);
  183. }
  184. /**
  185. * Gets single logout service for the requested binding.
  186. *
  187. * @param binding the binding
  188. * @return the single logout service or null
  189. */
  190. public SingleLogoutService getSingleLogoutService(final String binding) {
  191. return getSingleLogoutServices().stream().filter(acs -> acs.getBinding().equals(binding)).findFirst().orElse(null);
  192. }
  193. /**
  194. * Gets assertion consumer service.
  195. *
  196. * @param binding the binding
  197. * @return the assertion consumer service
  198. */
  199. public AssertionConsumerService getAssertionConsumerService(final String binding) {
  200. return getAssertionConsumerServices().stream().filter(acs -> acs.getBinding().equals(binding)).findFirst().orElse(null);
  201. }
  202. /**
  203. * Gets assertion consumer service for paos binding.
  204. *
  205. * @return the assertion consumer service for paos binding
  206. */
  207. public AssertionConsumerService getAssertionConsumerServiceForPaosBinding() {
  208. return getAssertionConsumerService(SAMLConstants.SAML2_PAOS_BINDING_URI);
  209. }
  210. /**
  211. * Gets assertion consumer service for post binding.
  212. *
  213. * @return the assertion consumer service for post binding
  214. */
  215. public AssertionConsumerService getAssertionConsumerServiceForPostBinding() {
  216. return getAssertionConsumerService(SAMLConstants.SAML2_POST_BINDING_URI);
  217. }
  218. /**
  219. * Gets assertion consumer service for artifact binding.
  220. *
  221. * @return the assertion consumer service for artifact binding
  222. */
  223. public AssertionConsumerService getAssertionConsumerServiceForArtifactBinding() {
  224. return getAssertionConsumerService(SAMLConstants.SAML2_ARTIFACT_BINDING_URI);
  225. }
  226. public MetadataResolver getMetadataResolver() {
  227. return this.metadataResolver;
  228. }
  229. /**
  230. * Contains assertion consumer services ?
  231. *
  232. * @return true/false
  233. */
  234. public boolean containsAssertionConsumerServices() {
  235. return !getAssertionConsumerServices().isEmpty();
  236. }
  237. /**
  238. * Assertion consumer services size.
  239. *
  240. * @return the size
  241. */
  242. public int assertionConsumerServicesSize() {
  243. return getAssertionConsumerServices().size();
  244. }
  245. }