2015-01-20 14 views
6

Ich verwende Spring SAML in einer mandantenfähigen Anwendung, um SSO bereitzustellen. Verschiedene Mandanten verwenden unterschiedliche URLs, um auf die Anwendung zuzugreifen, und für jeden Mandanten ist ein eigener Identitätsanbieter konfiguriert. Wie ordne ich automatisch den richtigen Identity Provider zu, wenn die URL für den Zugriff auf die Anwendung verwendet wird?Wie wähle ich automatisch den konfigurierten SAML-Identitätsprovider in einer mandantenfähigen Umgebung aus, um SSO mit Spring SAML auszuführen

Beispiel:

Mieter 1: http://tenant1.myapp.com

Mieter 2: http://tenant2.myapp.com

ich sah, dass ich einen Parameter IDP auf die URL hinzufügen können (http://tenant1.myapp.com?idp=my.idp.entityid.com) und der SAMLContextProvider die Identity-Provider wählen mit Diese Entitäts-ID. Ich habe einen datenbankgestützten MetadataProvider entwickelt, der den Mandanten hostname als Initialisierungsparameter verwendet, um die Metadaten für diesen Mandanten aus der Datenbank abzurufen, die mit diesem Hostnamen verknüpft ist. Jetzt denke ich, ich brauche eine Möglichkeit, über die Metadaten-Provider zu iterieren, um entityId der Metadaten mit dem Hostnamen zu verknüpfen. Ich sehe aber nicht, wie ich die entityId der Metadaten holen kann. Das würde mein Problem lösen.

Antwort

6

Sie können sehen, wie verfügbare EntityIDs aus einer MetadataProvider in Methode MetadataManager#parseProvider analysiert werden. Beachten Sie, dass jeder Anbieter im Allgemeinen mehrere IDP- und SP-Definitionen bereitstellen kann, nicht nur eine.

Alternativ können Sie weiterhin die ExtendedMetadataDelegate mit Ihrer eigenen Klasse erweitern, ist unabhängig von zusätzlichen Metadaten (wie EntityID) Sie wollen, und dann einfach MetadataProvider auf Ihre individuelle Klasse erneut eingeben und Informationen von dort erhalten, wenn Daten durch die MetadataManager Iterieren.

Wenn ich Sie wäre, würde ich ein etwas anderes Vorgehen wählen. Ich würde SAMLContextProviderImpl verlängern, Methode populatePeerEntityId überschreiben und den ganzen Matching von hostname/IDP dort durchführen. Einzelheiten finden Sie unter original method.

+3

Ich habe meinen eigenen SAMLContextProvider erstellt und die populatePeerIdentityId überschrieben. Das hat super funktioniert. Sobald ich fertig war, erkannte ich, dass der SAMLContextProvider nur während SP-initiierten SSO verwendet wird. Wir verwenden meistens IDP-initiierte SSO, also musste ich das ebenfalls abdecken.Am Ende habe ich die PeerEntityID der eingehenden Nachricht mit der IDP-Entitäts-ID verglichen, die für diesen Mandanten in meinem benutzerdefinierten SAMLAuthenticationProvider konfiguriert ist. – MarcFasel

+1

Diese Funktion zum Zuordnen von Identity Provider zu Service Provider ist der Schlüssel zur Unterstützung von Mandantenfähigkeit. Ist das in kommenden Releases geplant? – MarcFasel

+0

Wir werden sehen, das Projekt hängt von meiner Freizeit ab (es wird von niemandem gesponsert) und es gibt nicht viel davon. Die Verbesserung der Mandantenfähigkeit möchte ich gerne tun. –

3

Zum Zeitpunkt des Schreibens befindet sich Spring SAML in der Version 1.0.1.FINAL. Die Multi-Tenancy-Funktion wird nicht sofort unterstützt. Ich habe einen anderen Weg gefunden, um eine Mehrfachmiete zu erreichen, abgesehen von den Vorschlägen von Vladimir oben. Es ist sehr einfach und unkompliziert und erfordert keine Erweiterung von Spring SAML-Klassen. Darüber hinaus nutzt Spring SAML die integrierte Handhabung von Aliasen in CachingMetadataManager.

In Ihrem Controller, erfassen die Mieter Namen von der Anfrage und erstellen Sie ein Objekt ExtendedMetadata die Mieter Namen als Alias. Als nächstes erstellen Sie eine ExtendedMetadataDelegate aus der ExtendedMetadata und initialisieren Sie es. Analysieren Sie die Entity-IDs und prüfen Sie, ob sie in MetadataManager vorhanden sind. Wenn sie nicht vorhanden sind, fügen Sie den Anbieter hinzu und aktualisieren Sie die Metadaten. Dann erhalten Sie die Entity-ID von MetadataManager mit getEntityIdForAlias().

Hier ist der Code für den Controller. Es gibt Kommentare Inline einige Einschränkungen zu erklären:

@Controller 
public class SAMLController { 

    @Autowired 
    MetadataManager metadataManager; 

    @Autowired 
    ParserPool parserPool; 

    @RequestMapping(value = "/login.do", method = RequestMethod.GET) 
    public ModelAndView login(HttpServletRequest request, HttpServletResponse response, @RequestParam String tenantName) 
                 throws MetadataProviderException, ServletException, IOException{ 
     //load metadata url using tenant name 
     String tenantMetadataURL = loadTenantMetadataURL(tenantName); 

     //Deprecated constructor, needs to change 
     HTTPMetadataProvider httpMetadataProvider = new HTTPMetadataProvider(tenantMetadataURL, 15000); 
     httpMetadataProvider.setParserPool(parserPool); 

     //Create extended metadata using tenant name as the alias 
     ExtendedMetadata metadata = new ExtendedMetadata(); 
     metadata.setLocal(true); 
     metadata.setAlias(tenantName); 

     //Create metadata provider and initialize it 
     ExtendedMetadataDelegate metadataDelegate = new ExtendedMetadataDelegate(httpMetadataProvider, metadata); 
     metadataDelegate.initialize(); 

     //getEntityIdForAlias() in MetadataManager must only be called after the metadata provider 
     //is added and the metadata is refreshed. Otherwise, the alias will be mapped to a null 
     //value. The following code is a roundabout way to figure out whether the provider has already 
     //been added or not. 

     //The method parseProvider() has protected scope in MetadataManager so it was copied here   
     Set<String> newEntityIds = parseProvider(metadataDelegate); 
     Set<String> existingEntityIds = metadataManager.getIDPEntityNames(); 

     //If one or more IDP entity ids do not exist in metadata manager, assume it's a new provider. 
     //If we always add a provider without this check, the initialize methods in refreshMetadata() 
     //ignore the provider in case of a duplicate but the duplicate still gets added to the list 
     //of providers because of the call to the superclass method addMetadataProvider(). Might be a bug. 
     if(!existingEntityIds.containsAll(newEntityIds)) { 
      metadataManager.addMetadataProvider(metadataDelegate); 
      metadataManager.refreshMetadata(); 
     } 

     String entityId = metadataManager.getEntityIdForAlias(tenantName); 

     return new ModelAndView("redirect:/saml/login?idp=" + URLEncoder.encode(entityId, "UTF-8")); 
    } 

    private Set<String> parseProvider(MetadataProvider provider) throws MetadataProviderException { 
     Set<String> result = new HashSet<String>(); 

     XMLObject object = provider.getMetadata(); 
     if (object instanceof EntityDescriptor) { 
      addDescriptor(result, (EntityDescriptor) object); 
     } else if (object instanceof EntitiesDescriptor) { 
      addDescriptors(result, (EntitiesDescriptor) object); 
     } 

     return result; 

    } 

    private void addDescriptors(Set<String> result, EntitiesDescriptor descriptors) throws MetadataProviderException { 
     if (descriptors.getEntitiesDescriptors() != null) { 
      for (EntitiesDescriptor descriptor : descriptors.getEntitiesDescriptors()) { 
       addDescriptors(result, descriptor); 
      } 
     } 

     if (descriptors.getEntityDescriptors() != null) { 
      for (EntityDescriptor descriptor : descriptors.getEntityDescriptors()) { 
       addDescriptor(result, descriptor); 
      } 
     } 
    } 

    private void addDescriptor(Set<String> result, EntityDescriptor descriptor) throws MetadataProviderException { 
     String entityID = descriptor.getEntityID(); 
     result.add(entityID); 
    } 
} 

Ich glaube, das direkt das Problem des OP löst herauszufinden, wie für einen bestimmten Mieter das IDP zu bekommen. Dies funktioniert jedoch nur für IDPs mit einer einzelnen Entitäts-ID.

+0

Sehr nützlich! Danke für deinen ersten Post! – Zarial

+0

Ich möchte nur darauf hinweisen, dass diese Lösung nicht in einer Clusterumgebung funktioniert, es sei denn, Sie haben sticky-Sitzungen für Ihre Benutzer .... Die erste Anfrage an /login.do fügt jedoch den Metadatenanbieter zu der JVM hinzu, die dieser Anfrage zugeordnet ist Der Benutzer kann zu der App auf einer anderen JVM zurückkehren, die nicht den IDP kennt, der den Authentifizierungsprozess gestartet hat ... – danw

Verwandte Themen