2015-01-20 29 views
6

kullanarak SSO yapmak için yapılandırılmış SAML Kimlik sağlayıcısını bir çoklu kiracı ortamında otomatik olarak nasıl alabilirim? SSO sağlamak için çok kiracı uygulamasında Spring SAML kullanıyorum. Farklı kiracılar, uygulamaya erişmek için farklı URL'ler kullanır ve her birinin yapılandırılmış ayrı bir Kimlik Sağlayıcısı vardır. Uygulamaya erişmek için kullanılan URL'yi kullanarak doğru Kimlik Sağlayıcısını nasıl otomatik olarak atayabilirim?Bahar SAML

Örnek:

kiracı 1: http://tenant1.myapp.com

kiracı 2:

http://tenant2.myapp.com I kimlik sağlayıcı bulacaktır URL (http://tenant1.myapp.com?idp=my.idp.entityid.com) ve SAMLContextProvider bir parametre IDP eklenebileceğini gördü bu varlık id. Kiracı ana bilgisayar adını, o ana makine adına bağlı veritabanını oluşturan bu kiracı için meta verileri almak üzere başlangıç ​​parametresi olarak alan veritabanı destekli bir MetadataProvider geliştirdim. Şimdi meta veri sağlayıcıları üzerinden ana makine adına bağlantı kurmak için meta veri sağlayıcıları üzerinde yinelemenin bir yoluna ihtiyacım var. Yine de meta veriyi nasıl elde edebileceğimi göremiyorum. Bu benim problemimi çözecek.

cevap

6

Sen yöntemde MetadataManager#parseProvider bir MetadataProvider takım mevcut entityIDs ayrıştırmak için nasıl görebilirsiniz. Genellikle her bir sağlayıcının sadece bir değil, birden fazla IDP ve SP tanımlaması sağlayabileceğini unutmayın.

Alternatif olarak, daha fazla kendi sınıfı ile ExtendedMetadataDelegate uzatmak olabilir, (ENTITYID gibi) ne olursa olsun ek meta Arzu ve MetadataManager yoluyla veri yineleme zaman sonra sadece özelleştirilmiş sınıfına MetadataProvider yeniden yazın ve oradan bilgi alabilirsiniz bulunmaktadır.

Senin yerinde olsam bile, biraz farklı bir yaklaşım alırdım. SAMLContextProviderImpl'u uzatır, populatePeerEntityId geçersiz kılma yöntemini kullanır ve orada tüm ana makine adı/IDP eşleşmesini gerçekleştiririm. Detaylar için original method'a bakın.

+3

Kendi SAMLContextProvider'mı oluşturdum ve populatePeerIdentityId'yi geçersiz kıldım. Bu harika çalıştı. Bir kez bittikten sonra SAMLContextProvider'ın sadece SP tarafından başlatılan SSO sırasında kullanıldığını fark ettim. Çoğunlukla IDP tarafından başlatılan SSO kullanıyoruz, bu yüzden bunu da kapsamam gerekiyordu.Gelen iletinin peerEntityID değerini, özel SAMLAuthenticationProvider öğesinde bu kiracı için yapılandırılan IDP varlık kimliğine karşı kontrol ettim. – MarcFasel

+1

Kimlik sağlayıcıyı servis sağlayıcıya eşleme özelliğinin bu özelliği, çoklu kiralamayı desteklemenin anahtarıdır. Bu gelecek sürümlerde mi planlanıyor? – MarcFasel

+0

Göreceğiz, proje boş zamanıma bağlı (herkes tarafından desteklenmiyor) ve fazla bir şey yok. Çoklu kiracılığı geliştirmek, yapmak istediğim bir şeydir. –

3

Yazım sırasında, Spring SAML, 1.0.1.FINAL sürümündedir. Kutudan temiz bir şekilde çok kiracılığı desteklemez. Yukarıdaki Vladimir tarafından verilen önerilerin dışında çok kiracılığa ulaşmak için başka bir yol buldum. Çok basit ve düz ileri ve herhangi bir Spring SAML sınıfının genişletilmesini gerektirmez. Ayrıca, Spring SAML'nin CachingMetadataManager numaralı telefondaki takma adların kullanımını da kullanır. Kumandanızda olarak

, istekten kiracı adını yakalamak ve takma ad olarak kiracı adını kullanarak bir ExtendedMetadata nesne oluşturmak. Ardından, ExtendedMetadata'dan bir ExtendedMetadataDelegate oluşturun ve ilklendirin. Varlık kimliklerini bunun dışında ayrıştırın ve MetadataManager içinde olup olmadığını kontrol edin. Varsa, sağlayıcıyı ekleyin ve meta verileri yenileyin. Ardından, getEntityIdForAlias()'u kullanarak varlık kimliğini MetadataManager'dan alın.

Denetleyicinin kodu şöyledir. satır içi bazı uyarılar açıklayan yorumlar vardır:

@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); 
    } 
} 

bu direkt olarak belirli bir kiracı için IDP almak için nasıl bulmaktan OP'ın sorunu çözer inanıyoruz. Ancak bu, yalnızca tek bir varlık kimliğine sahip IDP'ler için çalışacaktır.

+0

Çok faydalı! İlk yazdığınız için teşekkürler! – Zarial

+0

Sadece kullanıcılarınız için yapışkan oturumlar olmadıkça bu çözümün kümelenmemiş bir ortamda çalışmadığını belirtmek istersiniz .... /login.do'ya yapılan ilk istek, meta veri sağlayıcısını bu istekle ilişkili JVM'ye ekler; Kullanıcı, kimlik doğrulama sürecini başlatan IDP'nin farkında olmayan başka bir JVM'de uygulamaya geri dönebilir ... – danw