Spring SAML extension for multiple IDP'S

2019-02-19 23:39发布

问题:

we are planning to use spring saml extension as SP into our application. But the requirement with our application is we need to communicate with more than 1 IDP's Could any one please provide me/direct me to the example where it uses multiple IDP's

I also would like to know spring saml extension supports what kind of IDPS like OPenAM/Ping federate/ADFs2.0 etc...

Thanks, --Vikas

回答1:

You can find all answers to your question in the Spring SAML manual.

The sample application which is included as part of the product already includes metadata for two IDPs, use it as an example.

Statement on IDPs is included in chapter 1.2:

All products supporting SAML 2.0 in Identity Provider mode (e.g. ADFS 2.0, Shibboleth, OpenAM/OpenSSO, Efecte Identity or Ping Federate) can be used with the extension.



回答2:

You need to have a class to maintain a list of metadatas of each Idp's - say you putting those metadatas in some list which will be shared across application by static method. I have something like below NOTE- I am not copying all class as it is that I am having, so might came across minor issues which you should be able to resolve on your own,

public class SSOMetadataProvider {
  public static List<MetadataProvider> metadataList() throws MetadataProviderException, XMLParserException, IOException, Exception {            
            logger.info("Starting : Loading Metadata Data for all SSO enabled companies...");
            List<MetadataProvider> metadataList = new ArrayList<MetadataProvider>();
            org.opensaml.xml.parse.StaticBasicParserPool parserPool = new org.opensaml.xml.parse.StaticBasicParserPool();
            parserPool.initialize();

            //Get XML from DB -> convertIntoInputStream -> pass below as const argument
            InputStreamMetadataProvider inputStreamMetadata = null;
            try {
        //Getting list from DB
                List companyList = someServiceClass.getAllSSOEnabledCompanyDTO();

                if(companyList!=null){
                    for (Object obj : companyList) {
                        CompanyDTO companyDTO = (CompanyDTO) obj;
                        if (companyDTO != null && companyDTO.getCompanyid() > 0 && companyDTO.getSsoSettingsDTO()!=null && !StringUtil.isNullOrEmpty(companyDTO.getSsoSettingsDTO().getSsoMetadataXml())) {
                            logger.info("Loading Metadata for Company : "+companyDTO.getCompanyname()+" , companyId : "+companyDTO.getCompanyid());

                            inputStreamMetadata = new InputStreamMetadataProvider(companyDTO.getSsoSettingsDTO().getSsoMetadataXml());
                            inputStreamMetadata.setParserPool(parserPool);
                            inputStreamMetadata.initialize();


                            //ExtendedMetadataDelegateWrapper extMetadaDel = new ExtendedMetadataDelegateWrapper(inputStreamMetadata , new org.springframework.security.saml.metadata.ExtendedMetadata());

                            SSOMetadataDelegate extMetadaDel = new SSOMetadataDelegate(inputStreamMetadata , new org.springframework.security.saml.metadata.ExtendedMetadata()) ;

                            extMetadaDel.initialize();
                            extMetadaDel.setTrustFiltersInitialized(true);
                            metadataList.add(extMetadaDel);

                            logger.info("Loading Metadata bla bla");


                        }
                    }
                }

            } catch (MetadataProviderException | IOException | XMLParserException  mpe){

                logger.warn(mpe);
                throw mpe;
            }
            catch (Exception e) {
                logger.warn(e);
            }

            logger.info("Finished : Loading Metadata Data for all SSO enabled companies...");

            return metadataList;
        }

InputStreamMetadataProvider.java

 public class InputStreamMetadataProvider extends AbstractReloadingMetadataProvider implements Serializable
    {
    public InputStreamMetadataProvider(String metadata) throws MetadataProviderException 
        {
            super();
            //metadataInputStream = metadata;
            metadataInputStream = SSOUtil.getIdpAsStream(metadata);

        }
@Override
    protected byte[] fetchMetadata() throws MetadataProviderException
    {
        byte[] metadataBytes = metadataInputStream ;

        if(metadataBytes.length>0)  
                return metadataBytes;
        else 
            return null;
    }
public byte[] getMetadataInputStream() {
    return metadataInputStream;
}
}

SSOUtil.java

public class SSOUtil {

    public static byte[] getIdpAsStream(String metadatXml) {


            return metadatXml.getBytes();


        }

}

After user request to fetch metadata for their company's metadata, get MetaData for entityId for each IdPs - SSOCachingMetadataManager.java

public class SSOCachingMetadataManager extends CachingMetadataManager{

 @Override
    public ExtendedMetadata getExtendedMetadata(String entityID) throws MetadataProviderException {
        ExtendedMetadata extendedMetadata = null;

        try {


            //UAT Defect Fix - org.springframework.security.saml.metadata.ExtendedMetadataDelegate cannot be cast to biz.bsite.direct.spring.app.sso.ExtendedMetadataDelegate
            //List<MetadataProvider> metadataList =  (List<MetadataProvider>) GenericCache.getInstance().getCachedObject("ssoMetadataList", List.class.getClassLoader());

            List<MetadataProvider> metadataList = SSOMetadataProvider.metadataList();

            log.info("Retrieved Metadata List from Cassendra Cache size is :"+ (metadataList!=null ? metadataList.size(): 0) );

            org.opensaml.xml.parse.StaticBasicParserPool parserPool = new org.opensaml.xml.parse.StaticBasicParserPool();
            parserPool.initialize();

            if(metadataList!=null){



                //metadataList.addAll(getAvailableProviders());
                //metadataList.addAll(getProviders());

                //To remove duplicate entries from list, if any
                Set<MetadataProvider> hs = new HashSet<MetadataProvider> ();
                hs.addAll(metadataList);

                metadataList.clear();
                metadataList.addAll(hs);
                //setAllProviders(metadataList);
                //setTrustFilterInitializedToTrue();
                //refreshMetadata();

            }


            if(metadataList!=null && metadataList.size()>0) {

                for(MetadataProvider metadataProvider :  metadataList){


                        log.info("metadataProvider instance of ExtendedMetadataDelegate: Looking for entityId"+entityID);

                        SSOMetadataDelegate ssoMetadataDelegate = null;                     
                        ExtendedMetadataDelegateWrapper extMetadaDel = null;

//                      extMetadaDel.getDelegate()
                        if(metadataProvider instanceof SSOMetadataDelegate)
                            {ssoMetadataDelegate = (SSOMetadataDelegate) metadataProvider;

                                ((InputStreamMetadataProvider)ssoMetadataDelegate.getDelegate()).setParserPool(parserPool);
                                ((InputStreamMetadataProvider)ssoMetadataDelegate.getDelegate()).initialize();
                                ssoMetadataDelegate.initialize();

                                ssoMetadataDelegate.setTrustFiltersInitialized(true);

                                if(!isMetadataAlreadyExist(ssoMetadataDelegate))
                                    addMetadataProvider(ssoMetadataDelegate);   

                                extMetadaDel = new ExtendedMetadataDelegateWrapper(ssoMetadataDelegate.getDelegate() , new org.springframework.security.saml.metadata.ExtendedMetadata());
                            }
                        else 
                            extMetadaDel = new ExtendedMetadataDelegateWrapper(metadataProvider, new org.springframework.security.saml.metadata.ExtendedMetadata());


                        extMetadaDel.initialize();
                        extMetadaDel.setTrustFiltersInitialized(true);

                        extMetadaDel.initialize();

                        refreshMetadata();

                        extendedMetadata = extMetadaDel.getExtendedMetadata(entityID);

                }
        }

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        if(extendedMetadata!=null)
            return extendedMetadata;  
        else{
            return super.getExtendedMetadata(entityID);                          
        }
    }



    private boolean isMetadataAlreadyExist(SSOMetadataDelegate ssoMetadataDelegate) {

        boolean isExist = false;
            for(ExtendedMetadataDelegate item :  getAvailableProviders()){

                    if (item.getDelegate() != null && item.getDelegate() instanceof SSOMetadataDelegate) {  

                        SSOMetadataDelegate that = (SSOMetadataDelegate) item.getDelegate();
                        try {

                            log.info("This Entity ID: "+ssoMetadataDelegate.getMetadata()!=null ?  ((EntityDescriptorImpl)ssoMetadataDelegate.getMetadata()).getEntityID() : "nullEntity"+

                                    "That Entity ID: "+that.getMetadata()!=null ?  ((EntityDescriptorImpl)that.getMetadata()).getEntityID() : "nullEntity");

                            EntityDescriptorImpl e = (EntityDescriptorImpl) that.getMetadata();

                        isExist = this.getMetadata()!=null ?  ((EntityDescriptorImpl)ssoMetadataDelegate.getMetadata()).getEntityID().equals(e.getEntityID()) : false;

                            if(isExist)
                                return isExist;
                        } catch (MetadataProviderException e1) {
                            // TODO Auto-generated catch block
                            e1.printStackTrace();
                        }

              }

            }
            return isExist;

    }

Add entry in ur Spring bean xml

<bean id="metadata" class="pkg.path.SSOCachingMetadataManager">
        <constructor-arg name="providers" value="#{ssoMetadataProvider.metadataList()}">
        </constructor-arg>
        <property name="RefreshCheckInterval" value="-1"/>
        <property name="RefreshRequired" value="false"/>
</bean>

Let me know incase of any concerns.



回答3:

I have recently configured two IDPs for Spring SAML extension. Here we should follow one basic rule. For each IDP we want to add, we have to configure one IDP provider as well as one SP provider. We should configure the providers in a MetadataManager bean, CachingMetadataManager for example. Here are some code snippets to get the idea what I am trying to say about:

public void addProvider(String providerMetadataUrl, String idpEntityId, String spEntityId, String alias) {
    addIDPMetadata(providerMetadataUrl, idpEntityId, alias);
    addSPMetadata(spEntityId, alias);
}

public void addIDPMetadata(String providerMetadataUrl, String idpEntityId, String alias) {
    try {           
        if (metadata.getIDPEntityNames().contains(idpEntityId)) {
            return;
        }
        metadata.addMetadataProvider(extendedMetadataProvider(providerMetadataUrl, alias));
    } catch (MetadataProviderException e1) {
        log.error("Error initializing metadata", e1);
    }
}

public void addSPMetadata(String spEntityId, String alias) {
    try {
        if (metadata.getSPEntityNames().contains(spEntityId)) {
            return;
        }           
        MetadataGenerator generator = new MetadataGenerator();
        generator.setEntityId(spEntityId);
        generator.setEntityBaseURL(baseURL);
        generator.setExtendedMetadata(extendedMetadata(alias));
        generator.setIncludeDiscoveryExtension(true);
        generator.setKeyManager(keyManager);

        EntityDescriptor descriptor = generator.generateMetadata();
        ExtendedMetadata extendedMetadata = generator.generateExtendedMetadata();
        MetadataMemoryProvider memoryProvider = new MetadataMemoryProvider(descriptor);
        memoryProvider.initialize();
        MetadataProvider metadataProvider = new ExtendedMetadataDelegate(memoryProvider, extendedMetadata);
        metadata.addMetadataProvider(metadataProvider);
        metadata.setHostedSPName(descriptor.getEntityID());
        metadata.refreshMetadata();
    } catch (MetadataProviderException e1) {
        log.error("Error initializing metadata", e1);
    }
}

public ExtendedMetadataDelegate extendedMetadataProvider(String providerMetadataUrl, String alias)
        throws MetadataProviderException {
    HTTPMetadataProvider provider = new HTTPMetadataProvider(this.bgTaskTimer, httpClient, providerMetadataUrl);
    provider.setParserPool(parserPool);
    ExtendedMetadataDelegate delegate = new ExtendedMetadataDelegate(provider, extendedMetadata(alias));
    delegate.setMetadataTrustCheck(true);
    delegate.setMetadataRequireSignature(false);
    return delegate;
}

private ExtendedMetadata extendedMetadata(String alias) {
    ExtendedMetadata exmeta = new ExtendedMetadata();
    exmeta.setIdpDiscoveryEnabled(true);
    exmeta.setSignMetadata(false);
    exmeta.setEcpEnabled(true);
    if (alias != null && alias.length() > 0) {
        exmeta.setAlias(alias);
    }

    return exmeta;
}