2015-01-20 11 views
6

का उपयोग करके एसएसओ करने के लिए मैं बहु-किरायेदार वातावरण में कॉन्फ़िगर किए गए SAML पहचान प्रदाता को स्वचालित रूप से कैसे चुनूं I एसएसओ प्रदान करने के लिए एक बहु-किरायेदार एप्लिकेशन में स्प्रिंग एसएएमएल का उपयोग कर रहा हूं। विभिन्न किरायेदार एप्लिकेशन तक पहुंचने के लिए विभिन्न यूआरएल का उपयोग करते हैं, और प्रत्येक के पास एक अलग पहचान प्रदाता कॉन्फ़िगर किया गया है। आवेदन को एक्सेस करने के लिए उपयोग किए जाने वाले यूआरएल को दिए गए सही पहचान प्रदाता को स्वचालित रूप से मैं कैसे असाइन करूं?स्प्रिंग SAML

उदाहरण:

किरायेदार 1: http://tenant1.myapp.com

किरायेदार 2: http://tenant2.myapp.com

मुझे लगता है कि मैं यूआरएल (http://tenant1.myapp.com?idp=my.idp.entityid.com) और SAMLContextProvider के लिए एक पैरामीटर आईडीपी जोड़ सकते हैं के साथ पहचान प्रदाता ले जाएगा देखा वह इकाई आईडी मैंने डेटाबेस-समर्थित मेटाडाटाप्रोवाइडर विकसित किया जो उस किरायेदार के लिए मेटाडेटा लाने के लिए प्रारंभिक पैरामीटर के रूप में किरायेदार होस्टनाम को उस होस्टनाम से लिंक किया गया डेटाबेस बनाता है। अब मुझे लगता है कि मेटाडेटा प्रदाताओं से मेजबाननाम में मेटाडेटा की इकाई को जोड़ने के लिए मुझे कुछ तरीकों की आवश्यकता है। मैं नहीं देखता कि मैं मेटाडेटा की इकाई आईडी कैसे प्राप्त कर सकता हूं। इससे मेरी समस्या हल हो जाएगी।

उत्तर

6

आप विधि MetadataManager#parseProvider में एक MetadataProvider से बाहर उपलब्ध entityIDs पार्स करने के लिए कैसे देख सकते हैं। ध्यान दें कि आम तौर पर प्रत्येक प्रदाता एकाधिक आईडीपी और एसपी परिभाषाओं की आपूर्ति कर सकता है, केवल एक ही नहीं।

वैकल्पिक रूप से, आप आगे अपने ही वर्ग के साथ ExtendedMetadataDelegate का विस्तार कर सकता है, (entityId) की तरह जो कुछ भी अतिरिक्त मेटाडेटा आप चाहते हैं, और फिर बस अपने अनुकूलित वर्ग के लिए MetadataProvider फिर से लिखें और वहाँ से जानकारी प्राप्त कर MetadataManager के माध्यम से डाटा पुनरावृत्ति शामिल हैं।

यदि मैं आप थे, तो मैं थोड़ा अलग दृष्टिकोण लेता हूं। मैं SAMLContextProviderImpl का विस्तार करूंगा, विधि populatePeerEntityId ओवरराइड करें और होस्टनाम/आईडीपी के सभी मिलान को निष्पादित करें। विवरण के लिए original method देखें।

+3

मैंने अपना स्वयं का SAMLContextProvider बनाया और populatePeerIdentityId को ओवरराइड किया। यह बहुत अच्छा काम किया। एक बार जब मैं किया गया तो मुझे एहसास हुआ कि SAMLContextProvider का उपयोग केवल एसपीओ एसएसओ के दौरान किया जाता है। हम ज्यादातर एसडीओ शुरू किए गए आईडीपी का उपयोग करते हैं, इसलिए मुझे इसे भी कवर करने की आवश्यकता होती है।मैंने आईडीपी इकाई आईडी के खिलाफ आने वाले संदेश की peerEntityID को जांचना समाप्त कर दिया जो कि मेरे कस्टम SAMLAuthenticationProvider में उस किरायेदार के लिए कॉन्फ़िगर किया गया है। – MarcFasel

+1

सेवा प्रदाता को पहचान प्रदाता मानचित्रण की यह विशेषता बहु-किरायेदारी का समर्थन करने के लिए महत्वपूर्ण है। क्या यह आगामी रिलीज में योजनाबद्ध है? – MarcFasel

+0

हम देखेंगे, परियोजना मेरे खाली समय पर निर्भर करती है (यह किसी के द्वारा प्रायोजित नहीं है) और इसमें से अधिकतर नहीं है। बहु-किरायेदारी में सुधार करना कुछ ऐसा है जो मैं करना चाहता हूं। –

3

लेखन के समय, स्प्रिंग एसएएमएल संस्करण 1.0.1 पर है। अंतिम। यह बॉक्स से बाहर बहु-किरायेदारी का समर्थन नहीं करता है। मुझे ऊपर व्लादिमीर द्वारा दिए गए सुझावों के अलावा बहु-किरायेदारी हासिल करने का एक और तरीका मिला। यह बहुत ही सरल और सीधा-आगे है और किसी भी स्प्रिंग एसएएमएल कक्षाओं के विस्तार की आवश्यकता नहीं है। इसके अलावा, यह स्प्रिंग SAML के CachingMetadataManager में उपनामों के अंतर्निर्मित हैंडलिंग का उपयोग करता है।

अपने नियंत्रक में, किरायेदार नाम को अनुरोध से कैप्चर करें और किरायेदार नाम का उपयोग उपनाम के रूप में ExtendedMetadata ऑब्जेक्ट बनाएं। इसके बाद ExtendedMetadata में से ExtendedMetadataDelegate बनाएं और इसे प्रारंभ करें। इसके बाहर इकाई आईडी को पार्स करें और जांचें कि क्या वे MetadataManager में मौजूद हैं या नहीं। यदि वे मौजूद नहीं हैं, तो प्रदाता जोड़ें और मेटाडेटा रीफ्रेश करें। फिर getEntityIdForAlias() का उपयोग कर से इकाई आईडी प्राप्त करें।

यहां नियंत्रक के लिए कोड है। टिप्पणियाँ इनलाइन कुछ चेतावनियां समझा रहे हैं:

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

मेरा मानना ​​है कि यह सीधे पता लगाना कैसे एक दिया किरायेदार के लिए आईडीपी पाने के लिए की ओपी के समस्या का हल। लेकिन यह केवल एक इकाई आईडी के साथ आईडीपी के लिए काम करेगा।

+0

बहुत उपयोगी! आपकी पहली पोस्ट के लिए धन्यवाद! – Zarial

+0

बस यह इंगित करना चाहते हैं कि यह समाधान क्लस्टर्ड वातावरण में तब तक काम नहीं करता जब तक कि आपके उपयोगकर्ताओं के लिए चिपचिपा सत्र न हो .... /login.do के प्रारंभिक अनुरोध मेटाडेटा प्रदाता को उस अनुरोध से जुड़े JVM में जोड़ता है, हालांकि उपयोगकर्ता किसी अन्य JVM पर ऐप पर वापस आ सकता है जो प्रमाणीकरण प्रक्रिया शुरू करने वाले आईडीपी से अवगत नहीं है ... – danw

संबंधित मुद्दे