हम SAML 2.0 के साथ SSO को एकीकृत करने में अपना अनुभव साझा करते हैं

1. पृष्ठभूमि

इस तथ्य के बावजूद कि एक केंद्रीकृत इनपुट (एकल साइन ऑन, एसएसओ) का कार्य मौजूद है, लंबे समय से चर्चा और आवेदन किया गया है, व्यवहार में इसका कार्यान्वयन अक्सर कई प्रकार की समस्याओं पर काबू पाने के साथ होता है। इस लेख का उद्देश्य यह दिखाना है कि SAML 2.0 पहचान प्रदाता (idP) के लिए सबसे सरल देशी सेवा प्रदाता 1 (SP) को कैसे लागू किया जाए और SSO को जावा वेब एप्लिकेशन में एकीकृत करने के लिए इसका उपयोग किया जाए।

हमारी हाल की परियोजनाओं में से एक बड़े विश्वविद्यालय के लिए एक पोर्टल समाधान की तैयारी और क्लस्टरिंग थी। परियोजना के ढांचे में, हमें निम्नलिखित प्रणालियों के लिए एकल प्रमाणीकरण समारोह को लागू करने के कार्य (साथ ही क्लस्टरिंग) का सामना करना पड़ा:

  1. लाइफ़रे संस्करण 6.1.20-ई-गा 2।
  2. सरल जावा वेब अनुप्रयोग।
  3. Google ऐप्स।

ग्राहक की ओर से, SSO के निर्माण की मुख्य आवश्यकताओं को सामने रखा गया:
  1. SSO बनाने के लिए, SAML 2.0 प्रोटोकॉल का उपयोग किया जाना चाहिए।
  2. मौजूदा सिस्टम को चालू रखने के लिए जैसिग कैस के साथ एकीकरण आवश्यक है।
  3. LDAP का उपयोग उपयोगकर्ता प्रमाणीकरण को सत्यापित करने के लिए किया जाता है।

उन्होंने एक खुले स्रोत प्रणाली के रूप में शिबोलेथ ( http://shibboleth.net/about/index.html ) का उपयोग करने का निर्णय लिया, जो SAML 1.0 && SAML 2.0 प्रोटोकॉल को पूर्ण रूप से लागू करता है।

इस समस्या को हल करने में हमारे सामने आए मुश्किल क्षण:

  1. एसएएमएल 2.0 प्रोटोकॉल और शिबोलेथ उत्पाद के साथ काम करने में विशेषज्ञता का अभाव।
  2. निर्माता से कच्चे और अभी तक अच्छी तरह से संरचित शिबोलेथ प्रलेखन नहीं।
  3. आपके जावा वेब एप्लिकेशन में SSO को एकीकृत करने के लिए सेवा प्रदाता के कार्यान्वयन के उच्च-गुणवत्ता वाले उदाहरणों की कमी।

इन बाधाओं पर काबू पाना इस लेख के प्रकाशन की प्रेरणा बन गया है। हम अर्जित ज्ञान को साझा करना चाहते हैं, डेवलपर्स ऐसी समस्याओं को हल करने में मदद करते हैं, और एसएएमएल 2.0 प्रोटोकॉल के साथ परिचित होने की सुविधा भी देते हैं।

2. लेख किसके लिए है?

यह लेख निम्नलिखित दर्शकों के लिए लक्षित है:
  1. डेवलपर्स जो एसएएमएल 2.0 का उपयोग करके अपनी परियोजनाओं में एसएसओ फ़ंक्शन को एकीकृत करते हैं।
  2. जावा डेवलपर्स जिन्हें एसएएमएल 2.0 के उपयोग से एसएसओ कार्यों को एकीकृत करने के व्यावहारिक उदाहरण की आवश्यकता है।
  3. जावा डेवलपर्स जो एक एसएसओ आइडेंटिटी प्रोवाइडर (आईडीपी) के रूप में शिबोलेथ घटक को आज़माना चाहते हैं।

लेख को समझने के लिए, यह अनुशंसा की जाती है कि आपको एसएएमएल 2.0 प्रोटोकॉल का न्यूनतम ज्ञान है।

3. एसएसओ के काम के मुख्य घटक

नीचे दिया गया चित्र हमारे केंद्रीकृत प्रवेश के समग्र कामकाज को दर्शाता है।



आरेख पर चिह्नित मुख्य घटक और बिंदु:
  1. SSO प्रणाली में 2 अनुप्रयोग शामिल हैं:
    एक। जावा वेब ऐप - एक नियमित जावा वेब एप्लिकेशन
    ख। Google Apps Google Cloud Services का एक एप्लिकेशन है। हम इसका उपयोग केवल एसएसओ के संचालन को सत्यापित करने के लिए करेंगे।
  2. एसपी फ़िल्टर - सेवा प्रदाता का कार्यान्वयन, जिसका कार्य SAML 2.0 संदेश भेजने और पार्स करने के माध्यम से शिबेल्थ आईडीपी के साथ बातचीत होगी।
  3. Shibboleth आईडीपी SAML 1.0 और SAML 2.0 का उपयोग करके प्रमाणीकरण और प्राधिकरण के लिए एक आवेदन पत्र है।
  4. टॉमकैट एएस - जावा एप्लिकेशन सर्वर।
  5. एसपी फ़िल्टर और शिबोलेथ आईडीपी के बीच बातचीत सुरक्षित HTTPS प्रोटोकॉल पर होती है।

नोट: शिबोलेथ आरेख में, आईडीपी और जावा वेब अनुप्रयोगों को अलग-अलग टॉमकैट सर्वरों के अलावा भौतिक रूप से स्थान दिया गया है। हालाँकि, आप अपने वातावरण को केवल एक टॉमकैट उदाहरण का उपयोग करके एकल नेटवर्क नोड में तैनात कर सकते हैं।

4. शिबोलेथ आईडीपी के लिए वातावरण तैयार करें

शिबोबल ईडीपी की स्थापना और विन्यास:

1. आईडीपी का नवीनतम संस्करण यहां डाउनलोड करें shibboleth.net/downloads/identity-provider/latest 2 और इसे अनियंत्रित स्थान $ shDistr पर अनज़िप करें
2. जांचें कि JAVA_HOME चर 3 सही रूप से सेट है।
हम $ shDistr / install.sh शुरू करते हैं (हम विचार करेंगे कि UNIX-like ऑपरेटिंग सिस्टम का उपयोग किया जाता है)। 4

इंस्टॉलर निम्नलिखित जानकारी को ध्यान में रखने के लिए कहेगा:

अगला, हम सत्यापित करते हैं कि स्थापना प्रक्रिया सफलतापूर्वक पूरी हो गई है।

हम निम्नलिखित संकेतन प्रस्तुत करते हैं:


3. हम निर्धारित करते हैं कि कौन सी विशेषताएँ और किन स्रोतों से आईडीपी निकाली जाएगी। हमारे मामले में, हम उपयोगकर्ता लॉगिन पास करेंगे। < Resolver : AttributeDefinition id = "transientId" xsi: type = "ad: TransientId" एलीमेंट के बाद फाइल विवरण को $ shHome / conf / विशेषता-resolver.xml में जोड़ें

<resolver:AttributeDefinition xsi:type="PrincipalName" xmlns="urn:mace:shibboleth:2.0:resolver:ad" id="userLogin" > <resolver:AttributeEncoder xsi:type="SAML1String" xmlns="urn:mace:shibboleth:2.0:attribute:encoder" name="userLogin" /> <resolver:AttributeEncoder xsi:type="SAML2String" xmlns="urn:mace:shibboleth:2.0:attribute:encoder" name="userLogin" /> </resolver:AttributeDefinition> 

नोट: एक ही फ़ाइल में आप JDBC के माध्यम से LDAP या DBMS जैसे विभिन्न डेटा स्रोतों से विशेषताओं की प्राप्ति को कॉन्फ़िगर कर सकते हैं। यहां पढ़ें https://wiki.shibboleth.net/confluence/display/SHIB2/IdPAddAttribute

4. इस SAML SP विशेषता को फ़िल्टर करने के लिए idP के लिए, हमने इसे $ shHome / conf / विशेषता-filter.xml फ़ाइल में वर्णित किया है।

 <afp:AttributeFilterPolicy id="releaseUserLoginToAnyone"> <afp:PolicyRequirementRule xsi:type="basic:ANY"/> <afp:AttributeRule attributeID="userLogin"> <afp:PermitValueRule xsi:type="basic:ANY"/> </afp:AttributeRule> </afp:AttributeFilterPolicy> 

नोट: यहां आप एक अधिक जटिल और सही नियम सेट कर सकते हैं। उदाहरण के लिए, आप यह निर्दिष्ट कर सकते हैं कि यह विशेषता केवल एक विशिष्ट एसएएमएल एसपी को पारित की जाए।

5. हमारी शिबोलेथ आईडीपी को उन नोड्स के बारे में पता होना चाहिए जिनके साथ वह बातचीत कर सकता है - तथाकथित भरोसा करने वाली पार्टी ( https://wiki.shibboleth.net/confluence/display/SHIB2/IdUUnderstandingRP )। यह जानकारी $ shHome / conf / relying-party.xml फ़ाइल में संग्रहीत है।
फ़ाइल खोलें और उसमें निम्न तत्व जोड़ें:

 <rp:RelyingParty id="sp.local.ru" provider="https://idp.local.ru/idp/shibboleth" defaultSigningCredentialRef="IdPCredential"> <rp:ProfileConfiguration xsi:type="saml:SAML2SSOProfile" signResponses="never" signAssertions="never" encryptNameIds="never" encryptAssertions="never" /> </rp:RelyingParty> 

यहां हम संकेत देते हैं कि सपा के लिए आईडी = "sp.local.ru" आईडी के साथ आईडी = " https://idp.local.ru/idp/shibboleth " का उपयोग किया जाएगा।

स्थानीय / होस्ट / होस्ट फ़ाइल के लिए उपनाम की सूची में SP जोड़ें:
127.0.0.1 लोकलहोस्ट sp.local.ru

हम shibboleth idP को SAML 2.0 प्रतिक्रियाओं और अभिकथनों के एक सेट पर हस्ताक्षर नहीं करने का भी निर्देश देते हैं। अब तक, हमारे शिबोलेथ आईडीपी को पता नहीं था कि आईडी = "sp.local.ru" के साथ एक घटक क्या था। इस पल को ठीक करने का समय। हम अगले चरण पर जाते हैं।

6. हमारे एसएएमएल 2.0 एसपी फिल्टर का विवरण जोड़ें। ऐसा करने के लिए, $ shHome / conf / relying-party.xml फ़ाइल में, हमारे SP के लिए मेटा-सूचना को परिभाषित करें, बगल में <मेटाडेटा: MetadataProvider id = "IdPMD" xsi: type = "metadata: FilesystemMetadataProvider" ...>

 <metadata:MetadataProvider id="spMD" xsi:type="metadata:FilesystemMetadataProvider" metadataFile="/opt/shib/metadata/saml-sp-metadata.xml"/> 

हमने shibboleth idP को निर्देश दिया है कि वह फ़ाइल में एक SP परिभाषा देखें /opt/shib/metadata/saml-sp-metadata.xml। इस फाइल को निम्न सामग्री से बनाएं:

 <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="sp.local.ru"> <md:SPSSODescriptor AuthnRequestsSigned="false" ID="sp.local.ru" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://sp.local.ru:8443/sso/acs" index="1" isDefault="true"/> </md:SPSSODescriptor> </md:EntityDescriptor> 

यहाँ आपको निम्नलिखित समझने की आवश्यकता है:


7. यह उस विधि को चुनने के लिए रहता है जिसके द्वारा shibboleth idP उपयोगकर्ताओं को प्रमाणित करेगा। उत्पादन के माहौल में, एलडीएपी, डीबीएमएस और यहां तक ​​कि सीएएस के माध्यम से प्रमाणीकरण सहित विभिन्न प्रकार के कॉन्फ़िगरेशन हो सकते हैं। यहाँ, जैसा कि वे कहते हैं, स्वाद और रंग। हम पहले से ही शामिल दूरस्थ उपयोगकर्ता प्रमाणीकरण तंत्र ( https://wiki.shibboleth.net/confluence/display/SHIB2/IdPAuthRemoteUser ) का उपयोग करेंगे। प्रमाणीकरण अनुरोध प्राप्त होने पर, shibboleth idP REMOTE_USER चर के संदर्भ में दिखेगा। यदि ऐसा कोई वैरिएबल है, तो शिबोलेथ आईडीपी यह मान लेगा कि उपयोगकर्ता पहले ही एक बाहरी सिस्टम (उदाहरण के लिए, वेब एपाचे सर्वर के माध्यम से) प्रमाणित कर चुका है। इस लेख को जटिल नहीं करने के लिए, हमने चाल में जाने और प्रत्येक अनुरोध के लिए REMOTE_USER चर को कृत्रिम रूप से सेट करने का निर्णय लिया।
टॉमकैट एएस (चरण 7) को कॉन्फ़िगर करते समय यह अगले भाग में किया जाएगा।

शिबेल्थ सेटअप पूरा हो गया है, बधाई :)

शिब्बू आइडीपी के लिए टॉमकैट को स्थापित और कॉन्फ़िगर करना:

  1. डाउनलोड tomcat 6 http://tomcat.apache.org/download-60.cgi , इसे मनमाने ढंग से $ tomcatHome फ़ोल्डर में अनज़िप करें (उदाहरण के लिए: opt / shib-tomcat में)।

    यह ध्यान रखना महत्वपूर्ण है कि फिलहाल, एसपीएपी और आईडीपी के बीच संचार सीधे एसओएपी के माध्यम से होने पर टॉमकैट 7. * का उपयोग नहीं किया जा सकता है। और यद्यपि इस लेख के उदाहरणों में हम इन संचारों को लागू करने के लिए ब्राउज़र के प्रत्यक्ष पुनर्निर्देशों का उपयोग करेंगे, हम अभी भी टॉमकैट संस्करण 6 का उपयोग करने की सलाह देते हैं।
  2. $ Shcistr / endorsed फ़ोल्डर में $ tomcatHome फ़ोल्डर की प्रतिलिपि बनाएँ।
  3. हम फ़ाइल $ tomcatHome / bin / setenv.s h को संशोधित करते हैं, गतिशील और स्थायी JVM फाइल के लिए सेटिंग्स सेट करें
    JAVA_OPTS = "$ JAVA_OPTS -Xmx512m -XX: MaxPermSize = 128m"
  4. लाइब्रेरी डाउनलोड करें ( https://build.shibboleth.net/nexus/content/repositories/releases/edu/internet2/middleware/security/tomcat6/tomcat6/dta-ssl/1.0.0/tomcat6-dta-ssl-1.0.0.0$ एसपीएच और आईडीपी के बीच संचार की प्रक्रिया में SOAP प्रोटोकॉल का समर्थन करने के लिए।
    $ TomcatHome / conf / server.xml खोलें और HTTPS के माध्यम से टमाटर तक पहुंच को कॉन्फ़िगर करें।
    ऐसा करने के लिए, निम्नलिखित कनेक्टर तत्व को परिभाषित करें:

     <Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol" SSLImplementation="edu.internet2.middleware.security.tomcat6.DelegateToApplicationJSSEmplementation" scheme="https" SSLEnabled="true" clientAuth="want" keystoreFile="$shHome/credentials/idp.jks" keystorePass="$shPassword" /> 


    चर को बदलने के लिए याद रखें $ shHome और $ shPassword वास्तविक मूल्यों के साथ
  5. Tomcat पर shibboleth आईडीपी ऐप तैनात करना। ऐसा करने के लिए, एक फ़ाइल बनाएं
    $ tomcatHome / conf / Catalina / localhost / idp.xml सामग्री के साथ:

     <Context docBase="$shHome/war/idp.war" privileged="true" antiResourceLocking="false" antiJARLocking="false" unpackWAR="false" swallowOutput="true" /> 


    $ ShHome चर को वास्तविक मान से प्रतिस्थापित करना याद रखें
  6. निम्न वर्ग को टोमसैट-वॉल्व में संकलित करें। पुस्तकालय मनमानी पुस्तकालय:

      public class RemoteUserValve extends ValveBase{ public RemoteUserValve() { } @Override public void invoke(final Request request, final Response response) throws IOException, ServletException { final String username = "idpuser"; final String credentials = "idppass"; final List<String> roles = new ArrayList<String>(); final Principal principal = new GenericPrincipal(null, username, credentials, roles); request.setUserPrincipal(principal); getNext().invoke(request, response); } } 

    लाइब्रेरी को $ {tomcatHome} / lib फ़ोल्डर में रखें। और server.xml फ़ाइल में एक पंक्ति जोड़ें
    <वाल्व lassName = "ru.eastbanctech.java.web.RemoteUserValve" / तत्व के अंदर
    <होस्ट नाम = "लोकलहोस्ट" ऐपबेस = "वेबैप्स" ..>। सर्वर शुरू होने के बाद, किसी भी टॉमकैट सर्वर एप्लिकेशन को एक्सेस करते समय, अनुरोध संदर्भ में idpuser मान के साथ REMOTE_USER पैरामीटर स्वचालित रूप से सेट हो जाएगा।

SAML 2.0 प्रोटोकॉल के लिए SP फ़िल्टर का कार्यान्वयन

इस समाधान को कार्यान्वित करने के लिए, एक SAML 2.0 सेवा प्रदाता फ़िल्टर बनाएं, जिसके कार्य निम्न होंगे:
  1. फ़िल्टर सार्वजनिक संसाधनों के लिए अनुरोध करता है जिसके लिए प्रमाणीकरण की आवश्यकता नहीं है।
  2. फिल्टर Shibboleth आईडीपी के लिए कॉल की संख्या को कम करने के लिए प्रमाणीकृत उपयोगकर्ता के बारे में जानकारी संग्रहीत करता है।
  3. फ़िल्टर SAML 2.0 संदेश ( AuthN ) के रूप में एक SAML 2.0 प्रमाणीकरण अनुरोध बनाता है और उपयोगकर्ता को Shibboleth idP पर पुनर्निर्देशित करने के लिए ब्राउज़र को पुनर्निर्देशित करता है।
  4. फ़िल्टर Shibboleth idP से प्रतिक्रिया की प्रक्रिया करता है, और यदि उपयोगकर्ता प्रमाणीकरण प्रक्रिया सफल होती है, तो सिस्टम मूल रूप से अनुरोधित संसाधन प्रदर्शित करता है।
  5. उपयोगकर्ता जावा वेब अनुप्रयोग से लॉग आउट होने पर फ़िल्टर स्थानीय सत्र को हटा देता है।
  6. इसी समय, शिबोलेथ आईडीपी पर सत्र सक्रिय रहना जारी है।


तकनीकी दृष्टिकोण से, फ़िल्टर मानक javax.filter.Filter इंटरफ़ेस का कार्यान्वयन होगा। फ़िल्टर का दायरा एक विशेष वेब एप्लिकेशन में सेट किया जाएगा।

अब जब फ़िल्टर की कार्यक्षमता स्पष्ट है, तो कार्यान्वयन के साथ आगे बढ़ें:
1. एक कंकाल मावेन परियोजना बनाएं
Mvn के माध्यम से किया जा सकता है:
mvan archetype: Generate -DgroupId = ru.eastbanctech.java.web -DartifactId = saml-sp-filter -DarchetypeArtifactId = मावेन-आर्किटाइप-क्विकार्टार्ट -डिनटेक्टिवमोड = असत्य
पैरामीटर groupId और artefactId आपके स्वाद और रंग को इंगित कर सकते हैं।
इंटेलीज आइडिया में हमारी परियोजना की संरचना इस तरह दिखाई देगी:


2. pom.xml विधानसभा फ़ाइल:

कोड
 <source lang="xml"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>ru.eastbanctech.web</groupId> <artifactId>saml-sp-filter</artifactId> <name>${project.artifactId}</name> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <properties> <jdk.version>1.6</jdk.version> <encoding>UTF-8</encoding> <project.build.sourceEncoding>${encoding}</project.build.sourceEncoding> <project.reporting.outputEncoding>${encoding}</project.reporting.outputEncoding> </properties> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.5.1</version> <configuration> <encoding>${encoding}</encoding> <soure>${jdk.version}</soure> <target>${jdk.version}</target> </configuration> </plugin> </plugins> </pluginManagement> </build> <dependency> <groupId>org.opensaml</groupId> <artifactId>opensaml</artifactId> <version>2.5.1-1</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>1.7.1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.1</version> </dependency> </dependencies> </project> 

3. हमारे फिल्टर का दिल SAMLSPFilter क्लास होगा:

 public class SAMLSPFilter implements Filter { public static final String SAML_AUTHN_RESPONSE_PARAMETER_NAME = "SAMLResponse"; private static Logger log = LoggerFactory.getLogger(SAMLSPFilter.class); private FilterConfig filterConfig; private SAMLResponseVerifier checkSAMLResponse; private SAMLRequestSender samlRequestSender; @Override public void init(javax.servlet.FilterConfig config) throws ServletException { OpenSamlBootstrap.init(); filterConfig = new FilterConfig(config); checkSAMLResponse = new SAMLResponseVerifier(); samlRequestSender = new SAMLRequestSender(); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; /*  1:  ,      2:     Shibboleth idP,    3:     logout,     4:    ,      5:  SAML        Shibboleth idP */ } } 


FilterConfig वर्ग में, हम मुख्य फिल्टर वेरिएबल्स (फिल्टर स्कोप, आईडीपी नाम, आईडीपी मेटाडेटा, एसपी नाम, आदि के लिए पथ) को परिभाषित करते हैं। इन मापदंडों का मान जावा वेब अनुप्रयोग के web.xml कॉन्फ़िगरेशन फ़ाइल में सेट किया जाएगा। SAMS 2.0 संदेशों की वैधता को सत्यापित करने और प्रमाणीकरण अनुरोध भेजने के लिए CheckSAMLResponse और samlRequestSender ऑब्जेक्ट की आवश्यकता है। हम थोड़ी देर बाद उनके पास लौट आएंगे।

कोड
 public class FilterConfig { /** * The parameters below should be defined in web.xml file of Java Web Application */ public static final String EXCLUDED_URL_PATTERN_PARAMETER = "excludedUrlPattern"; public static final String SP_ACS_URL_PARAMETER = "acsUrl"; public static final String SP_ID_PARAMETER = "spProviderId"; public static final String SP_LOGOUT_URL_PARAMETER = "logoutUrl"; public static final String IDP_SSO_URL_PARAMETER = "idProviderSSOUrl"; private String excludedUrlPattern; private String acsUrl; private String spProviderId; private String logoutUrl; private String idpSSOUrl; public FilterConfig(javax.servlet.FilterConfig config) { excludedUrlPattern = config.getInitParameter(EXCLUDED_URL_PATTERN_PARAMETER); acsUrl = config.getInitParameter(SP_ACS_URL_PARAMETER); spProviderId = config.getInitParameter(SP_ID_PARAMETER); idpSSOUrl = config.getInitParameter(IDP_SSO_URL_PARAMETER); logoutUrl = config.getInitParameter(SP_LOGOUT_URL_PARAMETER); } // getters and should be defined below }  OpenSamlBootstrap      SAML 2.0 : public class OpenSamlBootstrap extends DefaultBootstrap { private static Logger log = LoggerFactory.getLogger(OpenSamlBootstrap.class); private static boolean initialized; private static String[] xmlToolingConfigs = { "/default-config.xml", "/encryption-validation-config.xml", "/saml2-assertion-config.xml", "/saml2-assertion-delegation-restriction-config.xml", "/saml2-core-validation-config.xml", "/saml2-metadata-config.xml", "/saml2-metadata-idp-discovery-config.xml", "/saml2-metadata-query-config.xml", "/saml2-metadata-validation-config.xml", "/saml2-protocol-config.xml", "/saml2-protocol-thirdparty-config.xml", "/schema-config.xml", "/signature-config.xml", "/signature-validation-config.xml" }; public static synchronized void init() { if (!initialized) { try { initializeXMLTooling(xmlToolingConfigs); } catch (ConfigurationException e) { log.error("Unable to initialize opensaml DefaultBootstrap", e); } initializeGlobalSecurityConfiguration(); initialized = true; } } } 

XML फ़ाइलों के सेट में SAML 2.0 संदेशों के तत्वों को पार्स करने के निर्देश हैं और ओपनसमल में निहित है - * जार लाइब्रेरी, जो मावेन के माध्यम से प्रोजेक्ट बनाते समय कनेक्ट किया जाएगा।

चरण 1: फ़िल्टर के लिए इच्छित प्रश्नों को अनदेखा न करें
एक अतिरिक्त अभिव्यक्ति को अलग करता है, जो बाहर रखा गया है । यदि अनुरोध किया गया संसाधन बहिष्कृत डेटा टेम्पलेट में आता है, तो फ़िल्टर इसे संसाधित नहीं करता है:

 if (!isFilteredRequest(request)) { log.debug("According to {} configuration parameter request is ignored + {}", new Object[]{FilterConfig.EXCLUDED_URL_PATTERN, request.getRequestURI()}); chain.doFilter(servletRequest, servletResponse); return; } //     ,       private boolean isFilteredRequest(HttpServletRequest request) { return !(filterConfig.getExcludedUrlPattern() != null && getCorrectURL(request).matches(filterConfig.getExcludedUrlPattern())); } //       URL private String getCorrectURL(HttpServletRequest request) { String contextPath = request.getContextPath(); String requestUri = request.getRequestURI(); int contextBeg = requestUri.indexOf(contextPath); int contextEnd = contextBeg + contextPath.length(); String slash = "/"; String url = (contextBeg < 0 || contextEnd == (requestUri.length() - 1)) ? requestUri : requestUri.substring(contextEnd); if (!url.startsWith(slash)) { url = slash + url; } return url; } 


चरण 2: यदि प्रतिक्रिया शिबोलेथ आईडीपी से आई है, तो इसे संसाधित करें
हम अनुरोध में "SAMLResponse" पैरामीटर की तलाश कर रहे हैं और यदि यह पाया जाता है, तो हमें shibboleth idP से प्रमाणीकरण अनुरोध का जवाब मिला। SAML 2.0 संदेशों को संसाधित करना प्रारंभ करना।

कोड
 log.debug("Attempt to secure resource is intercepted : {}", ((HttpServletRequest) servletRequest).getRequestURL().toString()); /* Check if response message is received from identity provider; In case of successful response system redirects user to relayState (initial) request */ String responseMessage = servletRequest.getParameter(SAML_AUTHN_RESPONSE_PARAMETER_NAME); if (responseMessage != null) { log.debug("Response from Identity Provider is received"); try { log.debug("Decoding of SAML message"); SAMLMessageContext samlMessageContext = SAMLUtils.decodeSamlMessage((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse); log.debug("SAML message has been decoded successfully"); samlMessageContext.setLocalEntityId(filterConfig.getSpProviderId()); String relayState = getInitialRequestedResource(samlMessageContext); checkSAMLResponse.verify(samlMessageContext); log.debug("Starting and store SAML session.."); SAMLSessionManager.getInstance().createSAMLSession(request.getSession(), samlMessageContext); log.debug("User has been successfully authenticated in idP. Redirect to initial requested resource {}", relayState); response.sendRedirect(relayState); return; } catch (Exception e) { throw new ServletException(e); } } 


ऐसा करने के लिए, हम SAML संदेश को SAMLUtils.decodeSamlMessage (..) विधि में डिकोड करते हैं, और SAML कथनों को सत्यापित करने योग्य होते हैं - checkSAMLResponse.verify (..) । यदि सभी जांच पूरी हो गई हैं, तो एक आंतरिक SAML सत्र SAMLSessionManager.getInstance () बनाएँ। CreateSAMLSession (..) और मूल रूप से अनुरोधित प्रतिक्रिया के लिए उपयोगकर्ता को रीडायरेक्ट करें । SendRedirect (..) संसाधन

SAMLUtils वर्ग में, हम SAML 2.0 संदेशों के साथ काम करते समय उपयोगी मध्यवर्ती तरीके पोस्ट करेंगे। ऐसी ही एक विधि होगी डिकोडसमलैसमेज विधि, जो HTTPS SAML 2.0 के माध्यम से प्राप्त संदेशों को डिकोड करती है।
कोड
 public class SAMLUtils { public static SAMLMessageContext decodeSamlMessage(HttpServletRequest request, HttpServletResponse response) throws Exception { SAMLMessageContext<SAMLObject, SAMLObject, NameID> samlMessageContext = new BasicSAMLMessageContext<SAMLObject, SAMLObject, NameID>(); HttpServletRequestAdapter httpServletRequestAdapter = new HttpServletRequestAdapter(request); samlMessageContext.setInboundMessageTransport(httpServletRequestAdapter); samlMessageContext.setInboundSAMLProtocol(SAMLConstants.SAML20P_NS); HttpServletResponseAdapter httpServletResponseAdapter = new HttpServletResponseAdapter(response, request.isSecure()); samlMessageContext.setOutboundMessageTransport(httpServletResponseAdapter); samlMessageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME); SecurityPolicyResolver securityPolicyResolver = getSecurityPolicyResolver(request.isSecure()); samlMessageContext.setSecurityPolicyResolver(securityPolicyResolver); HTTPPostDecoder samlMessageDecoder = new HTTPPostDecoder(); samlMessageDecoder.decode(samlMessageContext); return samlMessageContext; } private static SecurityPolicyResolver getSecurityPolicyResolver(boolean isSecured) { SecurityPolicy securityPolicy = new BasicSecurityPolicy(); HTTPRule httpRule = new HTTPRule(null, null, isSecured); MandatoryIssuerRule mandatoryIssuerRule = new MandatoryIssuerRule(); List<SecurityPolicyRule> securityPolicyRules = securityPolicy.getPolicyRules(); securityPolicyRules.add(httpRule); securityPolicyRules.add(mandatoryIssuerRule); return new StaticSecurityPolicyResolver(securityPolicy); } } 

उसी कक्षा में, हम एसएएमएल ऑब्जेक्ट्स को स्ट्रिंग में परिवर्तित करने के लिए एक सहायक विधि रखेंगे। एसएएमएल संदेशों को लॉग करते समय यह उपयोगी होगा।
 public static String SAMLObjectToString(XMLObject samlObject) { try { Marshaller marshaller = org.opensaml.Configuration.getMarshallerFactory().getMarshaller(samlObject); org.w3c.dom.Element authDOM = marshaller.marshall(samlObject); StringWriter rspWrt = new StringWriter(); XMLHelper.writeNode(authDOM, rspWrt); return rspWrt.toString(); } catch (Exception e) { e.printStackTrace(); } return null; } 

चलो SAMLResponseVerifier वर्ग बनाते हैं, जिसमें हम SAMB 2.0 संदेशों को शिबोलेथ आईडीपी से प्राप्त होने वाले संदेशों की जाँच करने के लिए कार्यक्षमता देते हैं। मुख्य सत्यापन (..) विधि में, हम निम्नलिखित जांचों को लागू करते हैं:


कोड
 public class SAMLResponseVerifier { private static Logger log = LoggerFactory.getLogger(SAMLResponseVerifier.class); private SAMLRequestStore samlRequestStore = SAMLRequestStore.getInstance(); public void verify(SAMLMessageContext<Response, SAMLObject, NameID> samlMessageContext) throws SAMLException { Response samlResponse = samlMessageContext.getInboundSAMLMessage(); log.debug("SAML Response message : {}", SAMLUtils.SAMLObjectToString(samlResponse)); verifyInResponseTo(samlResponse); Status status = samlResponse.getStatus(); StatusCode statusCode = status.getStatusCode(); String statusCodeURI = statusCode.getValue(); if (!statusCodeURI.equals(StatusCode.SUCCESS_URI)) { log.warn("Incorrect SAML message code : {} ", statusCode.getStatusCode().getValue()); throw new SAMLException("Incorrect SAML message code : " + statusCode.getValue()); } if (samlResponse.getAssertions().size() == 0) { log.error("Response does not contain any acceptable assertions"); throw new SAMLException("Response does not contain any acceptable assertions"); } Assertion assertion = samlResponse.getAssertions().get(0); NameID nameId = assertion.getSubject().getNameID(); if (nameId == null) { log.error("Name ID not present in subject"); throw new SAMLException("Name ID not present in subject"); } log.debug("SAML authenticated user " + nameId.getValue()); verifyConditions(assertion.getConditions(), samlMessageContext); } private void verifyInResponseTo(Response samlResponse) { String key = samlResponse.getInResponseTo(); if (!samlRequestStore.exists(key)) { { log.error("Response does not match an authentication request"); throw new RuntimeException("Response does not match an authentication request"); } samlRequestStore.removeRequest(samlResponse.getInResponseTo()); } private void verifyConditions(Conditions conditions, SAMLMessageContext samlMessageContext) throws SAMLException{ verifyExpirationConditions(conditions); verifyAudienceRestrictions(conditions.getAudienceRestrictions(), samlMessageContext); } private void verifyExpirationConditions(Conditions conditions) throws SAMLException { log.debug("Verifying conditions"); DateTime currentTime = new DateTime(DateTimeZone.UTC); log.debug("Current time in UTC : " + currentTime); DateTime notBefore = conditions.getNotBefore(); log.debug("Not before condition : " + notBefore); if ((notBefore != null) && currentTime.isBefore(notBefore)) throw new SAMLException("Assertion is not conformed with notBefore condition"); DateTime notOnOrAfter = conditions.getNotOnOrAfter(); log.debug("Not on or after condition : " + notOnOrAfter); if ((notOnOrAfter != null) && currentTime.isAfter(notOnOrAfter)) throw new SAMLException("Assertion is not conformed with notOnOrAfter condition"); } private void verifyAudienceRestrictions( List<AudienceRestriction> audienceRestrictions, SAMLMessageContext<?, ?, ?> samlMessageContext) throws SAMLException{ // TODO: Audience restrictions should be defined below<sup>7</sup> } } 


VerInResponseTo विधि पुष्टि करती है कि SAML 2.0 प्रतिक्रिया हमारे फ़िल्टर से एक अनुरोध से पहले थी। कार्यान्वयन के लिए, SAMLRequestStore वर्ग की एक वस्तु का उपयोग किया जाता है, जो SAML 2.0 को भेजे गए अनुरोधों को shibboleth idP में संग्रहीत करता है।
कोड
 final public class SAMLRequestStore { private Set<String> samlRequestStorage = new HashSet<String>(); private IdentifierGenerator identifierGenerator = new RandomIdentifierGenerator(); private static SAMLRequestStore instance = new SAMLRequestStore(); private SAMLRequestStore() { } public static SAMLRequestStore getInstance() { return instance; } public synchronized void storeRequest(String key) { if (samlRequestStorage.contains(key)) throw new RuntimeException("SAML request storage has already contains key " + key); samlRequestStorage.add(key); } public synchronized String storeRequest(){ String key = null; while (true) { key = identifierGenerator.generateIdentifier(20); if (!samlRequestStorage.contains(key)){ storeRequest(key); break; } } return key; } public synchronized boolean exists(String key) { return samlRequestStorage.contains(key); } public synchronized void removeRequest(String key) { samlRequestStorage.remove(key); } } 



एक स्थानीय सत्र बनाने के लिए, हम अपने स्वयं के SAMLSessionManager वर्ग का उपयोग करेंगे। उसका कार्य स्थानीय सत्र बनाना / नष्ट करना होगा, जो कि निम्नलिखित SAMLSessionInfo वर्ग का एक उद्देश्य है।

 public class SAMLSessionInfo { private String nameId; private Map<String, String> attributes; private Date validTo; public SAMLSessionInfo(String nameId, Map<String, String> attributes, Date validTo) { this.nameId = nameId; this.attributes = attributes; this.validTo = validTo; } // getters should be defined below } 

वास्तव में, SAMLSessionManager वर्ग ही, जो SAMLContext का उपयोग करके सर्वर के सत्र संदर्भ में स्थानीय SAML सत्र बनाता और नष्ट करता है।
कोड
 <source lang="java"> public class SAMLSessionManager { public static String SAML_SESSION_INFO = "SAML_SESSION_INFO"; private static SAMLSessionManager instance = new SAMLSessionManager(); private SAMLSessionManager() { } public static SAMLSessionManager getInstance() { return instance; } public void createSAMLSession(HttpSession session, SAMLMessageContext<Response, SAMLObject, NameID> samlMessageContext) { List<Assertion> assertions = samlMessageContext.getInboundSAMLMessage().getAssertions(); NameID nameId = (assertions.size() != 0 && assertions.get(0).getSubject() != null) ? assertions.get(0).getSubject().getNameID() : null; String nameValue = nameId == null ? null : nameId.getValue(); SAMLSessionInfo samlSessionInfo = new SAMLSessionInfo(nameValue, getAttributesMap(getSAMLAttributes(assertions)), getSAMLSessionValidTo(assertions)); session.setAttribute(SAML_SESSION_INFO, samlSessionInfo); } public boolean isSAMLSessionValid(HttpSession session) { SAMLSessionInfo samlSessionInfo = (SAMLSessionInfo) session.getAttribute(SAML_SESSION_INFO); if (samlSessionInfo == null) return false; return samlSessionInfo.getValidTo() == null || new Date().before(samlSessionInfo.getValidTo()); } public void destroySAMLSession(HttpSession session) { session.removeAttribute(SAML_SESSION_INFO); } public List<Attribute> getSAMLAttributes(List<Assertion> assertions) { List<Attribute> attributes = new ArrayList<Attribute>(); if (assertions != null) { for (Assertion assertion : assertions) { for (AttributeStatement attributeStatement : assertion.getAttributeStatements()) { for (Attribute attribute : attributeStatement.getAttributes()) { attributes.add(attribute); } } } } return attributes; } public Date getSAMLSessionValidTo(List<Assertion> assertions) { org.joda.time.DateTime sessionNotOnOrAfter = null; if (assertions != null) { for (Assertion assertion : assertions) { for (AuthnStatement statement : assertion.getAuthnStatements()) { sessionNotOnOrAfter = statement.getSessionNotOnOrAfter(); } } } return sessionNotOnOrAfter != null ? sessionNotOnOrAfter.toCalendar(Locale.getDefault()).getTime() : null; } public Map<String, String> getAttributesMap(List<Attribute> attributes) { Map<String, String> result = new HashMap<String, String>(); for (Attribute attribute : attributes) { result.put(attribute.getName(), attribute.getDOM().getTextContent()); } return result; } } 


चरण 3: यदि लॉगआउट अनुरोध प्राप्त होता है, तो स्थानीय सत्र हटाएं

 if (getCorrectURL(request).equals(filterConfig.getLogoutUrl())) { log.debug("Logout action: destroying SAML session."); SAMLSessionManager.getInstance().destroySAMLSession(request.getSession()); chain.doFilter(request, response); return; } 

नोट: यह ध्यान देने योग्य है कि सत्र शिबोलेथ आईडीपी पर सक्रिय रहता है और अगले प्रमाणीकरण अनुरोध पर, शिबोलेथ आईडीपी बस हमें सक्रिय सत्र लौटा देगा। वैश्विक लॉगआउट के कार्यान्वयन के लिए अतिरिक्त सेटिंग्स की आवश्यकता होती है, और संस्करण 2.4.0 से पहले shibboleth idP समर्थित नहीं था। अधिक जानकारी यहां पाया जा सकता है https://wiki.shibboleth.net/confluence/display/SHIB2/SLOIssues

चरण 4: यदि उपयोगकर्ता पहले से ही प्रमाणित है, तो संसाधन तक पहुंच प्रदान करें

यदि उपयोगकर्ता के पास हमारे फ़िल्टर में सक्रिय SAML सत्र है, तो उपयोगकर्ता को यह संसाधन दें।
 if (SAMLSessionManager.getInstance().isSAMLSessionValid(request.getSession())) { log.debug("SAML session exists and valid: grant access to secure resource"); chain.doFilter(request, response); return; } 


चरण 5: हम SAML प्रमाणीकरण अनुरोध बनाते हैं और उपयोगकर्ता को
Shibboleth idP पर भेजते हैं


 log.debug("Sending authentication request to idP"); try { samlRequestSender .sendSAMLAuthRequest(request, response, filterConfig.getSpProviderId(), filterConfig.getAcsUrl(), filterConfig.getIdpSSOUrl()); } catch (Exception e) { throw new ServletException(e); } 

SAMLRequestSender वर्ग SAML 2.0 संदेशों के रूप में अनुरोध बनाता है, एन्कोड करता है और भेजता है।

कोड
 <source lang="java"> public class SAMLRequestSender { private static Logger log = LoggerFactory.getLogger(SAMLRequestSender.class); private SAMLAuthnRequestBuilder samlAuthnRequestBuilder = new SAMLAuthnRequestBuilder(); private MessageEncoder messageEncoder = new MessageEncoder(); public void sendSAMLAuthRequest(HttpServletRequest request, HttpServletResponse servletResponse, String spId, String acsUrl, String idpSSOUrl) throws Exception { String redirectURL; String idpUrl = idpSSOUrl; AuthnRequest authnRequest = samlAuthnRequestBuilder.buildRequest(spId, acsUrl, idpUrl); // store SAML 2.0 authentication request String key = SAMLRequestStore.getInstance().storeRequest(); authnRequest.setID(key); log.debug("SAML Authentication message : {} ", SAMLUtils.SAMLObjectToString(authnRequest)); redirectURL = messageEncoder.encode(authnRequest, idpUrl, request.getRequestURI()); HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(servletResponse, request.isSecure()); HTTPTransportUtils.addNoCacheHeaders(responseAdapter); HTTPTransportUtils.setUTF8Encoding(responseAdapter); responseAdapter.sendRedirect(redirectURL); } private static class SAMLAuthnRequestBuilder { public AuthnRequest buildRequest(String spProviderId, String acsUrl, String idpUrl){ /* Building Issuer object */ IssuerBuilder issuerBuilder = new IssuerBuilder(); Issuer issuer = issuerBuilder.buildObject("urn:oasis:names:tc:SAML:2.0:assertion", "Issuer", "saml2p"); issuer.setValue(spProviderId); /* Creation of AuthRequestObject */ DateTime issueInstant = new DateTime(); AuthnRequestBuilder authRequestBuilder = new AuthnRequestBuilder(); AuthnRequest authRequest = authRequestBuilder.buildObject(SAMLConstants.SAML20P_NS, "AuthnRequest", "saml2p"); authRequest.setForceAuthn(false); authRequest.setIssueInstant(issueInstant); authRequest.setProtocolBinding(SAMLConstants.SAML2_POST_BINDING_URI); authRequest.setAssertionConsumerServiceURL(acsUrl); authRequest.setIssuer(issuer); authRequest.setNameIDPolicy(nameIdPolicy); authRequest.setVersion(SAMLVersion.VERSION_20); authRequest.setDestination(idpUrl); return authRequest; } } private static class MessageEncoder extends HTTPRedirectDeflateEncoder { public String encode(SAMLObject message, String endpointURL, String relayState) throws MessageEncodingException { String encodedMessage = deflateAndBase64Encode(message); return buildRedirectURL(endpointURL, relayState, encodedMessage); } public String buildRedirectURL(String endpointURL, String relayState, String message) throws MessageEncodingException { URLBuilder urlBuilder = new URLBuilder(endpointURL); List<Pair<String, String>> queryParams = urlBuilder.getQueryParams(); queryParams.clear(); queryParams.add(new Pair<String, String>("SAMLRequest", message)); if (checkRelayState(relayState)) { queryParams.add(new Pair<String, String>("RelayState", relayState)); } return urlBuilder.buildURL(); } } } 

उपयोगकर्ता को प्रमाणीकृत करने के निर्देशों के साथ एक SAML 2.0 संदेश बिल्डरैप्सेस्ट विधि में बनाया गया है और एक एक्सएमएल ऑब्जेक्ट है:

 <saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceURL="https://sp.local.ru:8443/sso/acs" Destination="https://idp.local.ru:8443/idp/profile/SAML2/Redirect/SSO" ForceAuthn="false" ID="_0ddb303f9500839762eabd30e7b1e3c28b596c69" IssueInstant="2013-09-12T09:46:41.882Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0"> <saml2p:Issuer xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:assertion">sp.local.ru</saml2p:Issuer> </saml2p:AuthnRequest> 


AssertionConsumerServiceURL पैरामीटर उस URL को निर्दिष्ट करता है जिस पर shibboleth idP प्रतिसाद देगा, और प्रोटोकॉलबाइंडिंग पैरामीटर हमारे फ़िल्टर (POST HTTP प्रोटोकॉल विधि) पर प्रतिक्रिया कैसे लौटाता है
, ID पैरामीटर संदेश पहचानकर्ता को
बताता है कि जब हम संदेश भेजते हैं, तो हम संदेश भेजते हैं कुंजी # SAMLRequestStore.getInstance। storeRequest ();
और जाँच जब एक विधि में संदेशों को पार्स verifyInResponseTo वर्ग SAMLResponseVerifier

Saml2p: जारीकर्ता तत्व हमारे एसपी के नाम को परिभाषित करता है। Saml2p के मान का उपयोग करना : जारीकर्ता shibboleth idP यह निर्धारित करता है कि किस SP से प्रमाणीकरण अनुरोध भेजा गया था, और इसे कैसे संसाधित किया जाना चाहिए (SP मेटाडेटा के माध्यम से)।

उपरोक्त SAML 2.0 संदेश के जवाब में, हम XML प्रारूप में SAML 2.0 संदेश के रूप में idP से प्रतिक्रिया प्राप्त करेंगे:

कोड
 <source lang="xml"> <saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://sp.local.ru:8443/sso/acs" ID="_9c5e6028df334510cce22409ddbca6ac" InResponseTo="_0ddb303f9500839762eabd30e7b1e3c28b596c69" IssueInstant="2013-09-12T10:13:35.177Z" Version="2.0"> <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity"> https://idp.local.ru/idp/shibboleth </saml2:Issuer> <saml2p:Status> <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </saml2p:Status> <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="_0a299e86f4b17b5e047735121a880ccb" IssueInstant="2013-09-12T10:13:35.177Z" version="2.0"> <saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity"> https://idp.local.ru/idp/shibboleth </saml2:Issuer> <saml2:Subject> <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" NameQualifier="https://idp.local.ru/idp/shibboleth"> _f1de09ee54294d4b5ddeb3aa5e6d2aab </saml2:NameID> <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml2:SubjectConfirmationData Address="127.0.0.1" InResponseTo="_0ddb303f9500839762eabd30e7b1e3c28b596c69" NotOnOrAfter="2013-09-12T10:18:35.177Z" Recipient="https://sp.local.ru:8443/sso/acs"/> </saml2:SubjectConfirmation> </saml2:Subject> <saml2:Conditions NotBefore="2013-09-12T10:13:35.177Z" NotOnOrAfter="2013-09-12T10:18:35.177Z"> <saml2:AudienceRestriction> <saml2:Audience>sp.local.ru</saml2:Audience> </saml2:AudienceRestriction> </saml2:Conditions> <saml2:AuthnStatement AuthnInstant="2013-09-12T10:13:35.137Z" SessionIndex="_91826738984ca8bef18a8450135b1821"> <saml2:SubjectLocality Address="127.0.0.1"/> <saml2:AuthnContext> <saml2:AuthnContextClassRef> urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport </saml2:AuthnContextClassRef> </saml2:AuthnContext> </saml2:AuthnStatement> <saml2:AttributeStatement> <saml2:Attribute Name="userLogin" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">idpuser</saml2:AttributeValue> </saml2:Attribute> </saml2:AttributeStatement> </saml2:Assertion> </saml2p:Response> 

संदेश पहले से ही लागू SAMLResponseVerifier.verify (..) विधि में संसाधित किया जाएगा।
यह सब, हमारे फ़िल्टर लागू किया गया है!
हमारी परियोजना की संरचना इस तरह दिखती है:


हम स्थानीय पुस्तकालय में जार लाइब्रेरी में कार्यान्वित फ़िल्टर एकत्र करते हैं।
ऐसा करने के लिए, निर्देशिका में pom.xml के साथ कमांड चलाएँ : mvan clean install

6. एसएसओ समर्थन के साथ एक जावा वेब एप्लिकेशन बनाएं

एक जावा वेब अनुप्रयोग बनाएँ

एक उदाहरण के लिए, हम निजी और सार्वजनिक संसाधनों के साथ एक सरल जावा वेब एप्लिकेशन बनाएंगे। निजी संसाधनों तक पहुंच के लिए शिबोलेथ आईडीपी वेब एप्लिकेशन के माध्यम से उपयोगकर्ता प्रमाणीकरण की आवश्यकता होती है। हम एक निजी संसाधन को एक पेज बनाते हैं जो सिस्टम के वर्तमान उपयोगकर्ता पर जानकारी प्रदर्शित करता है।
हमारे आवेदन की संरचना इस प्रकार है:


pom.xml

कोड
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId> ru.eastbanctech.web</groupId> <artifactId>SimpleSSOApplication</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>SimpleSSOApplication</name> <url>http://maven.apache.org</url> <!--      --> <properties> <sp.id>sp.local.ru</sp.id> <acs.url>https://sp.local.ru:8443/sso/acs</acs.url> <idp.sso.url>https://idp.local.ru:8443/idp/profile/SAML2/Redirect/SSO</idp.sso.url> <logout.url>/logout</logout.url> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId> ru.eastbanctech.web</groupId> <artifactId>saml-sp-filter</artifactId> <version>1.0-SNAPSHOT</version> </dependency><sup>8</sup> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.1</version> </dependency> </dependencies> <build> <finalName>sso</finalName> <plugins> <plugin> <artifactId>maven-war-plugin</artifactId> <configuration> <webResources> <resource> <filtering>true</filtering> <directory>src/main/webapp/WEB-INF</directory> <targetPath>WEB-INF</targetPath> <includes> <include>**/*.xml</include> </includes> </resource> </webResources> </configuration> </plugin> </plugins> </build> </project> 

यहां आपको गुणों के अनुभाग की ओर मुड़ना होगा , जहां हमारे फ़िल्टर के मुख्य पैरामीटर
<sp.id> sp.local.ru </sp.id> सेट किए गए हैं - फ़िल्टर SP
<acs.url> https://sp.local.ru का SAML 2.0 नाम। 8443 / sso / acs </acs.url> - फ़िल्टर URL, जिसके द्वारा यह
shibboleth idP से SAML 2.0 संदेशों को संसाधित करेगा
<idp.sso.url> https://idp.local.ru:8443/idp/profile/SAML2 / रीडायरेक्ट / SSO </idp.sso.url> - URL
जहां हमारा फ़िल्टर संदेश भेज देगा idibleth idP
<logout.url> / logout </logout.url> - logout URL

web.xml

web.xml फ़ाइल में हम मापदंडों को परिभाषित करते हैं। हमारे फिल्टर और इसके दायरे। चलो ".jpg" प्रारूप में संसाधन बनाते हैंबाहर रखा हुआ खुला पैरामीटर

कोड
 <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Simple SSO Java Web Application</display-name>7. <filter> <filter-name>SSOFilter</filter-name> <filter-class> ru.eastbanctech.java.web.filter.saml.SAMLSPFilter</filter-class> <init-param> <param-name>excludedUrlPattern</param-name> <param-value>.*\.jpg</param-value> </init-param> <init-param> <param-name>idProviderSSOUrl</param-name> <param-value> ${idp.sso.url}</param-value> </init-param> <init-param> <param-name>spProviderId</param-name> <param-value>${sp.id}</param-value> </init-param> <init-param> <param-name>acsUrl</param-name> <param-value>${acs.url}</param-value> </init-param> <init-param> <param-name>logoutUrl</param-name> <param-value>${logout.url}</param-value> </init-param> </filter> <filter-mapping> <filter-name>SSOFilter</filter-name> <url-pattern>/pages/private/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>SSOFilter</filter-name> <url-pattern>${logout.url}</url-pattern> </filter-mapping> <filter-mapping> <filter-name>SSOFilter</filter-name> <url-pattern>/acs</url-pattern> </filter-mapping> </web-app> 


निजी / page.jsp

पृष्ठ केवल प्रमाणीकृत उपयोगकर्ता की आईडी और विशेषताओं का आउटपुट है।

कोड
 <%@ page import=" ru.eastbanctech.java.web.filter.saml.store.SAMLSessionManager" %> <%@ page import=" ru.eastbanctech.java.web.filter.saml.store.SAMLSessionInfo" %> <%@ page import="java.util.Map" %> <html> <body> <h2>Private Resource</h2> <% SAMLSessionInfo info = (SAMLSessionInfo)request.getSession().getAttribute(SAMLSessionManager.SAML_SESSION_INFO); out.println("User id = " + info.getNameId() + " "); out.println("<TABLE> <TR> <TH> Attribute name </TH> <TH> Attribulte value </TH></TR>"); for (Map.Entry entry : info.getAttributes().entrySet()) { out.println("<TR><TD>" + entry.getKey() + "</TD><TD>" + entry.getValue() + "</TD></TR>"); } out.println("</TABLE>"); %> <a href="<%=request.getContextPath()%>/logout">Logout</a> </body> </html> 

हम एप्लिकेशन को कमांड के साथ इकट्ठा करते हैं: mvan क्लीन पैकेज।

जावा वेब अनुप्रयोग प्रदर्शन का परीक्षण

हम टॉमकैट एएस में आवेदन को तैनात करते हैं और एसएसओ के संचालन की जांच करते हैं:
  1. हम फ़ाइल $ {tomcatHome} /conf/Catalina/localhost/sc.ml पर फ़ाइल के संदर्भ में वर्णन करते हैं
     <Context docBase="$pathToWebApp" privileged="true" antiResourceLocking="false" antiJARLocking="false" unpackWAR="false" swallowOutput="true" /> 


    या बस हमारे sso.war एप्लिकेशन को $ {tomcatHome} / वेबऐप में कॉपी करें
  2. HTTPS से अधिक shibboleth idP से कनेक्ट करने में सक्षम होने के लिए tomcat अनुप्रयोगों के लिए, आपको jib keystore में shibboleth idP प्रमाणपत्र जोड़ने की आवश्यकता है।
    ऐसा करने के लिए, Java यूटिलिटी

    कीटूल का उपयोग करें: कीटल-आलिया idp.local.ru -importcert -file $ {shHome} /idp.crt -keystore $ {keystorePath}
  3. टॉमकैट एएस लॉन्च करें
  4. हम ब्राउज़र खोलते हैं और sp.local.ru एप्लिकेशन के बंद संसाधन पर दस्तक देते हैं : 8443 / sso / पेज / प्राइवेट / पेज ।jsp
  5. जांचें कि पेज खुलता है और सिस्टम आईडी और उपयोगकर्ता नाम प्रदर्शित करता है

  6. एक अभ्यास के रूप में, यह सत्यापित करें कि फ़िल्टर .jpg प्रारूप में / पृष्ठों / निजी फ़ोल्डर में चित्रों के लिए अनुरोध करता है।

Google Apps के साथ एकीकरण।

अब यह जांचने का समय है कि एसएसओ वास्तव में हमारे लिए काम करता है।
ऐसा करने के लिए, हम Google Apps क्लाउड सेवाओं ( http://www.google.com/enterprise/apps/business/ ) से एप्लिकेशन का उपयोग करेंगे

  1. नि: शुल्क परीक्षण का उपयोग करके अपने डोमेन नाम और सुपर-व्यवस्थापक को पंजीकृत करें। सब कुछ पूरा होने के बाद, निर्मित उपयोगकर्ता (पूरी तरह से योग्य डोमेन नाम का उपयोग करके) के तहत admin.google.com सिस्टम पर जाएं
  2. idpuser, Super Administrator.
  3. « »
    «».

  4. -> .
  5. :
    URL * = https://idp.local.ru:8443/idp/profile/SAML2/Redirect/SSO
    URL * = gmail.com
    URL * = gmail.com

    .
  6. shibboleth idP HTTPS
    $shHome/credentials/idp.crt


    .
  7. https://shibboleth.usc.edu/docs/google-apps/ shibboleth idP Google Apps.

    : , shibboleth idP. , RelyingParty rp:RelyingParty.
  8. logger' edu.internet2.middleware.shibboleth DEBUG
      <!-- Logs IdP, but not OpenSAML, messages --> <logger name="edu.internet2.middleware.shibboleth" level="DEBUG"/> 

    shibboleth idP https://admin.google.com ( , Google Chrome ).
    idpuser@ domain_name , domain_name – . «».
    , google apps idpuser.
    ${shHome}/logs/idp-process.log , shibboleth idP . , RemoteUserLoginHandler
     22:19:49.172 - DEBUG [edu.internet2.middleware.shibboleth.idp.authn.provider.RemoteUserLoginHandler:66] - Redirecting to <a href="https://idp.local.ru:8443/idp/Authn/RemoteUser">https://idp.local.ru:8443/idp/Authn/RemoteUser</a> 


    shibboleth idP . , .
    sp.local.ru :8443/sso/pages/private/page.jsp
    , shibboleth idP idpuser.

    खैर, यह सब है। SSO . , - .

    नोट

    1 — Service Provider . Shibboleth , Apache- Application Server'.
    2 — Shibboleth idP 2.4.0
    3 — Java 7 .
    4 — CentOS 6.3 OS. Ubuntu 12.04.
    5 — servlet-api 2.5 ${tomcatHome}/lib/catalina.jar
    6 — ru.eastbanctech.java.web.RemoteUserValve – RemoteUserValve. .
    7 — .
    8 — .

    उपयोगी लिंक

    1. https://developers.google.com/google-apps/sso/saml_reference_implementation — SSO Google Apps. SSO Google Docs SAML.
    2. https://shibboleth.usc.edu/docs/google-apps/ — Shibboleth Google docs.
    3. http://stackoverflow.com/questions/7553967/getting-a-value-from-httpservletrequest-getremoteuser-in-tomcat-without-modify — Tomcat Valve
    4. https://wiki.shibboleth.net/confluence/display/SHIB2/Home — Shibboleth

Source: https://habr.com/ru/post/In193662/


All Articles