各位新年好,上海的新年好冷,冷到我手发抖。
做好准备全身心投入到新的学习和工作中去了吗?因为今天开始的教程很“变态”啊,我们要完成下面几件事:
上次我们说到了CAS SSO的一些基本用法如:连数据库怎么用,连LDAP怎么用,这次我们要来讲一个网上几乎没有人去过多涉及到的一个问题即:在多租户的环境下我们的cas sso如何去更好的支持,即cas sso multi tentant 的问题,这个问题在很多国外的一些网站包括CAS的官网也很少有人得到解决,在此呢我们把它给彻底的解决掉吧,呵呵。
什么是多租户环境呢?举个例子吧:
我们知道,在有一些云平台或者是电商中的B2B中,经常会存在这样的情况:
在同一个域名下如taobao.com下会有多个商铺(就是租户)好比:
<bean class=" org.sky.cas.auth.CASLDAPAuthenticationHandler" p:filter="uid=%u" p:searchBase="o=101,o=company,dc=sky,dc=org" p:contextSource-ref="contextSource" /> <bean class=" org.sky.cas.auth.CASLDAPAuthenticationHandler" p:filter="uid=%u" p:searchBase="o=102,o=company,dc=sky,dc=org" p:contextSource-ref="contextSource" /> <bean class=" org.sky.cas.auth.CASLDAPAuthenticationHandler" p:filter="uid=%u" p:searchBase="o=103,o=company,dc=sky,dc=org" p:contextSource-ref="contextSource" />
再来看看用于今天练习的我们在LDAP中的组织结构是怎么样的吧。
看到上面这张图了吧,这就是我说的“多租户”的概念,大家应该记得我们在CAS SSO第二天中怎么去拿CAS SSO绑定LDAP中的一条UserDN然后去搜索的吧?
<bean class=" org.sky.cas.auth.CASLDAPAuthenticationHandler" p:filter="uid=%u" p:searchBase="o=company,dc=sky,dc=org" p:contextSource-ref="contextSource" />对吧!!!
现在我们要做到的就是:
p:searchBase="xxx.xxx.xx"
这条要做成动态的,比如说:
前面我们提到过,这些配置是放在XML文件中的,因此每次增加一个”租户“我们要手工在XML配置文件中新增一条,这个不现实,它是实现不了我们的24*7的这种服务的要求的,我们要做的是可以让这个p:searchBase能够动态的去组建这个userDN,所以重点是要解决这个问题。
该问题在国外的YALE CAS论坛上有两种解决方案:
<class>org.jasig.cas.services.AbstractRegisteredService</class> <class>org.jasig.cas.services.RegexRegisteredService</class> <class>org.jasig.cas.services.RegisteredServiceImpl</class> <class>org.jasig.cas.ticket.TicketGrantingTicketImpl</class> <class>org.jasig.cas.ticket.ServiceTicketImpl</class> <class>org.jasig.cas.ticket.registry.support.JpaLockingStrategy$Lock</class>
<class>org.jasig.cas.services.AbstractRegisteredService</class> <class>org.jasig.cas.services.RegexRegisteredService</class> <class>org.jasig.cas.services.RegisteredServiceImpl</class> <class>org.jasig.cas.ticket.TicketGrantingTicketImpl</class> <class>org.jasig.cas.ticket.ServiceTicketImpl</class> <class>org.jasig.cas.ticket.registry.support.JpaLockingStrategy$Lock</class> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" /> </properties>这是完整的改完后的persistence.xml文件的内容:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0"> <persistence-unit name="CasPersistence" transaction-type="RESOURCE_LOCAL"> <class>org.jasig.cas.services.AbstractRegisteredService</class> <class>org.jasig.cas.services.RegexRegisteredService</class> <class>org.jasig.cas.services.RegisteredServiceImpl</class> <class>org.jasig.cas.ticket.TicketGrantingTicketImpl</class> <class>org.jasig.cas.ticket.ServiceTicketImpl</class> <class>org.jasig.cas.ticket.registry.support.JpaLockingStrategy$Lock</class> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" /> </properties> </persistence-unit> </persistence>
<bean id="log4jInitialization" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="targetClass" value="org.springframework.util.Log4jConfigurer"/> <property name="targetMethod" value="initLogging"/> <property name="arguments"> <list> <value>${log4j.config.location:classpath:log4j.xml}</value> <value>${log4j.refresh.interval:60000}</value> </list> </property> </bean>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- <bean id="log4jInitialization" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="targetClass" value="org.springframework.util.Log4jConfigurer"/> <property name="targetMethod" value="initLogging"/> <property name="arguments"> <list> <value>${log4j.config.location:classpath:log4j.xml}</value> <value>${log4j.refresh.interval:60000}</value> </list> </property> </bean> --> </beans>
public class CASCredential extends RememberMeUsernamePasswordCredentials { private static final long serialVersionUID = 1L; private Map<String, Object> param; private String companyid; /** * @return the companyid */ public String getCompanyid() { return companyid; } /** * @param companyid the companyid to set */ public void setCompanyid(String companyid) { this.companyid = companyid; } public Map<String, Object> getParam() { return param; } public void setParam(Map<String, Object> param) { this.param = param; } }
<view-state id="viewLoginForm" view="casLoginView" model="credentials"> <binder> <binding property="username" /> <binding property="password" /> </binder>
<view-state id="viewLoginForm" view="casLoginView" model="credentials"> <binder> <binding property="username" /> <binding property="password" /> <binding property="companyid"/> </binder>
package org.sky.cas.auth; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.validation.constraints.NotNull; import org.jasig.cas.CentralAuthenticationService; import org.jasig.cas.authentication.handler.AuthenticationException; import org.jasig.cas.authentication.principal.Credentials; import org.jasig.cas.authentication.principal.Service; import org.jasig.cas.ticket.TicketException; import org.jasig.cas.web.bind.CredentialsBinder; import org.jasig.cas.web.support.WebUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.binding.message.MessageBuilder; import org.springframework.binding.message.MessageContext; import org.springframework.util.StringUtils; import org.springframework.web.util.CookieGenerator; import org.springframework.webflow.core.collection.MutableAttributeMap; import org.springframework.webflow.execution.RequestContext; @SuppressWarnings("deprecation") public class CASAuthenticationViaFormAction { /** * Binder that allows additional binding of form object beyond Spring * defaults. */ private CredentialsBinder credentialsBinder; /** Core we delegate to for handling all ticket related tasks. */ @NotNull private CentralAuthenticationService centralAuthenticationService; @NotNull private CookieGenerator warnCookieGenerator; protected Logger logger = LoggerFactory.getLogger(getClass()); public final void doBind(final RequestContext context, final Credentials credentials) throws Exception { final HttpServletRequest request = WebUtils.getHttpServletRequest(context); if (this.credentialsBinder != null && this.credentialsBinder.supports(credentials.getClass())) { this.credentialsBinder.bind(request, credentials); } } public final String submit(final RequestContext context, final Credentials credentials, final MessageContext messageContext) throws Exception { String companyid = ""; // Validate login ticket final String authoritativeLoginTicket = WebUtils.getLoginTicketFromFlowScope(context); final String providedLoginTicket = WebUtils.getLoginTicketFromRequest(context); if (credentials instanceof CASCredential) { String companyCode = "compnayid"; CASCredential rmupc = (CASCredential) credentials; companyid = rmupc.getCompanyid(); } if (!authoritativeLoginTicket.equals(providedLoginTicket)) { this.logger.warn("Invalid login ticket " + providedLoginTicket); final String code = "INVALID_TICKET"; messageContext.addMessage(new MessageBuilder().error().code(code).arg(providedLoginTicket).defaultText(code).build()); return "error"; } final String ticketGrantingTicketId = WebUtils.getTicketGrantingTicketId(context); final Service service = WebUtils.getService(context); if (StringUtils.hasText(context.getRequestParameters().get("renew")) && ticketGrantingTicketId != null && service != null) { try { final String serviceTicketId = this.centralAuthenticationService.grantServiceTicket(ticketGrantingTicketId, service, credentials); WebUtils.putServiceTicketInRequestScope(context, serviceTicketId); putWarnCookieIfRequestParameterPresent(context); return "warn"; } catch (final TicketException e) { if (isCauseAuthenticationException(e)) { populateErrorsInstance(e, messageContext); return getAuthenticationExceptionEventId(e); } this.centralAuthenticationService.destroyTicketGrantingTicket(ticketGrantingTicketId); if (logger.isDebugEnabled()) { logger.debug("Attempted to generate a ServiceTicket using renew=true with different credentials", e); } } } try { CASCredential rmupc = (CASCredential) credentials; WebUtils.putTicketGrantingTicketInRequestScope(context, centralAuthenticationService.createTicketGrantingTicket(rmupc)); putWarnCookieIfRequestParameterPresent(context); return "success"; } catch (final TicketException e) { populateErrorsInstance(e, messageContext); if (isCauseAuthenticationException(e)) return getAuthenticationExceptionEventId(e); return "error"; } } private void populateErrorsInstance(final TicketException e, final MessageContext messageContext) { try { messageContext.addMessage(new MessageBuilder().error().code(e.getCode()).defaultText(e.getCode()).build()); } catch (final Exception fe) { logger.error(fe.getMessage(), fe); } } private void putWarnCookieIfRequestParameterPresent(final RequestContext context) { final HttpServletResponse response = WebUtils.getHttpServletResponse(context); if (StringUtils.hasText(context.getExternalContext().getRequestParameterMap().get("warn"))) { this.warnCookieGenerator.addCookie(response, "true"); } else { this.warnCookieGenerator.removeCookie(response); } } private AuthenticationException getAuthenticationExceptionAsCause(final TicketException e) { return (AuthenticationException) e.getCause(); } private String getAuthenticationExceptionEventId(final TicketException e) { final AuthenticationException authEx = getAuthenticationExceptionAsCause(e); if (this.logger.isDebugEnabled()) this.logger.debug("An authentication error has occurred. Returning the event id " + authEx.getType()); return authEx.getType(); } private boolean isCauseAuthenticationException(final TicketException e) { return e.getCause() != null && AuthenticationException.class.isAssignableFrom(e.getCause().getClass()); } public final void setCentralAuthenticationService(final CentralAuthenticationService centralAuthenticationService) { this.centralAuthenticationService = centralAuthenticationService; } /** * Set a CredentialsBinder for additional binding of the HttpServletRequest * to the Credentials instance, beyond our default binding of the * Credentials as a Form Object in Spring WebMVC parlance. By the time we * invoke this CredentialsBinder, we have already engaged in default binding * such that for each HttpServletRequest parameter, if there was a JavaBean * property of the Credentials implementation of the same name, we have set * that property to be the value of the corresponding request parameter. * This CredentialsBinder plugin point exists to allow consideration of * things other than HttpServletRequest parameters in populating the * Credentials (or more sophisticated consideration of the * HttpServletRequest parameters). * * @param credentialsBinder the credentials binder to set. */ public final void setCredentialsBinder(final CredentialsBinder credentialsBinder) { this.credentialsBinder = credentialsBinder; } public final void setWarnCookieGenerator(final CookieGenerator warnCookieGenerator) { this.warnCookieGenerator = warnCookieGenerator; } }
if (credentials instanceof CASCredential) { String companyCode = "compnayid"; CASCredential rmupc = (CASCredential) credentials; companyid = rmupc.getCompanyid(); }
CASCredential rmupc = (CASCredential) credentials; WebUtils.putTicketGrantingTicketInRequestScope(context, centralAuthenticationService.createTicketGrantingTicket(rmupc));它告诉了CAS SSO使用我们自定义的CASCredential来验证用户在CAS SSO中的登录信息,而不是原来CAS SSO默认的UsernameAndPasswordCredential。
<bean id="authenticationViaFormAction" class="org.jasig.cas.web.flow.AuthenticationViaFormAction" p:centralAuthenticationService-ref="centralAuthenticationService" p:warnCookieGenerator-ref="warnCookieGenerator"/>把它注释掉改成:
<!-- <bean id="authenticationViaFormAction" class="org.jasig.cas.web.flow.AuthenticationViaFormAction" p:centralAuthenticationService-ref="centralAuthenticationService" p:warnCookieGenerator-ref="warnCookieGenerator"/> --> <bean id="authenticationViaFormAction" class="org.sky.cas.auth.CASAuthenticationViaFormAction" p:centralAuthenticationService-ref="centralAuthenticationService" p:warnCookieGenerator-ref="warnCookieGenerator" />
package org.sky.cas.auth; import org.jasig.cas.adaptors.ldap.AbstractLdapUsernamePasswordAuthenticationHandler; import org.jasig.cas.authentication.handler.AuthenticationException; import org.jasig.cas.authentication.principal.UsernamePasswordCredentials; import org.jasig.cas.util.LdapUtils; import org.springframework.ldap.NamingSecurityException; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.NameClassPairCallbackHandler; import org.springframework.ldap.core.SearchExecutor; import javax.naming.NameClassPair; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.directory.SearchControls; import javax.validation.constraints.Max; import javax.validation.constraints.Min; import java.util.ArrayList; import java.util.List; public class CASLDAPAuthenticationHandler extends AbstractLdapUsernamePasswordAuthenticationHandler { /** The default maximum number of results to return. */ private static final int DEFAULT_MAX_NUMBER_OF_RESULTS = 1000; /** The default timeout. */ private static final int DEFAULT_TIMEOUT = 1000; /** The search base to find the user under. */ private String searchBase; /** The scope. */ @Min(0) @Max(2) private int scope = SearchControls.ONELEVEL_SCOPE; /** The maximum number of results to return. */ private int maxNumberResults = DEFAULT_MAX_NUMBER_OF_RESULTS; /** The amount of time to wait. */ private int timeout = DEFAULT_TIMEOUT; /** Boolean of whether multiple accounts are allowed. */ private boolean allowMultipleAccounts; protected final boolean authenticateUsernamePasswordInternal(final UsernamePasswordCredentials credentials) throws AuthenticationException { CASCredential rmupc = (CASCredential) credentials; final String companyid = rmupc.getCompanyid(); final List<String> cns = new ArrayList<String>(); final SearchControls searchControls = getSearchControls(); final String transformedUsername = getPrincipalNameTransformer().transform(credentials.getUsername()); final String filter = LdapUtils.getFilterWithValues(getFilter(), transformedUsername); try { this.getLdapTemplate().search(new SearchExecutor() { public NamingEnumeration executeSearch(final DirContext context) throws NamingException { String baseDN = ""; if (companyid != null && companyid.trim().length() > 0) { baseDN = "o=" + companyid + "," + searchBase; } else { baseDN = searchBase; } //System.out.println("searchBase=====" + baseDN); return context.search(baseDN, filter, searchControls); } }, new NameClassPairCallbackHandler() { public void handleNameClassPair(final NameClassPair nameClassPair) { cns.add(nameClassPair.getNameInNamespace()); } }); } catch (Exception e) { log.error("search ldap error casue: " + e.getMessage(), e); return false; } if (cns.isEmpty()) { log.debug("Search for " + filter + " returned 0 results."); return false; } if (cns.size() > 1 && !this.allowMultipleAccounts) { log.warn("Search for " + filter + " returned multiple results, which is not allowed."); return false; } for (final String dn : cns) { DirContext test = null; String finalDn = composeCompleteDnToCheck(dn, credentials); try { this.log.debug("Performing LDAP bind with credential: " + dn); test = this.getContextSource().getContext(finalDn, getPasswordEncoder().encode(credentials.getPassword())); if (test != null) { return true; } } catch (final NamingSecurityException e) { log.debug("Failed to authenticate user {} with error {}", credentials.getUsername(), e.getMessage()); return false; } catch (final Exception e) { this.log.error(e.getMessage(), e); return false; } finally { LdapUtils.closeContext(test); } } return false; } protected String composeCompleteDnToCheck(final String dn, final UsernamePasswordCredentials credentials) { return dn; } private SearchControls getSearchControls() { final SearchControls constraints = new SearchControls(); constraints.setSearchScope(this.scope); constraints.setReturningAttributes(new String[0]); constraints.setTimeLimit(this.timeout); constraints.setCountLimit(this.maxNumberResults); return constraints; } /** * Method to return whether multiple accounts are allowed. * @return true if multiple accounts are allowed, false otherwise. */ protected boolean isAllowMultipleAccounts() { return this.allowMultipleAccounts; } /** * Method to return the max number of results allowed. * @return the maximum number of results. */ protected int getMaxNumberResults() { return this.maxNumberResults; } /** * Method to return the scope. * @return the scope */ protected int getScope() { return this.scope; } /** * Method to return the search base. * @return the search base. */ protected String getSearchBase() { return this.searchBase; } /** * Method to return the timeout. * @return the timeout. */ protected int getTimeout() { return this.timeout; } public final void setScope(final int scope) { this.scope = scope; } /** * @param allowMultipleAccounts The allowMultipleAccounts to set. */ public void setAllowMultipleAccounts(final boolean allowMultipleAccounts) { this.allowMultipleAccounts = allowMultipleAccounts; } /** * @param maxNumberResults The maxNumberResults to set. */ public final void setMaxNumberResults(final int maxNumberResults) { this.maxNumberResults = maxNumberResults; } /** * @param searchBase The searchBase to set. */ public final void setSearchBase(final String searchBase) { this.searchBase = searchBase; } /** * @param timeout The timeout to set. */ public final void setTimeout(final int timeout) { this.timeout = timeout; } /** * Sets the context source for LDAP searches. This method may be used to * support use cases like the following: * <ul> * <li>Pooling of LDAP connections used for searching (e.g. via instance * of {@link org.springframework.ldap.pool.factory.PoolingContextSource}).</li> * <li>Searching with client certificate credentials.</li> * </ul> * <p> * If this is not defined, the context source defined by * {@link #setContextSource(ContextSource)} is used. * * @param contextSource LDAP context source. */ public final void setSearchContextSource(final ContextSource contextSource) { setLdapTemplate(new LdapTemplate(contextSource)); } }
<property name="authenticationHandlers"> <list> <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler" p:httpClient-ref="httpClient" /> <bean class=" org.sky.cas.auth.CASLDAPAuthenticationHandler" p:filter="uid=%u" p:searchBase="o=company,dc=sky,dc=org" p:contextSource-ref="contextSource" /> </list> </property>
final String companyid = rmupc.getCompanyid();
public NamingEnumeration executeSearch(final DirContext context) throws NamingException { String baseDN = ""; if (companyid != null && companyid.trim().length() > 0) { baseDN = "o=" + companyid + "," + searchBase; } else { baseDN = searchBase; } //System.out.println("searchBase=====" + baseDN); return context.search(baseDN, filter, searchControls); } }, new NameClassPairCallbackHandler() {
<bean id="authenticationManager" class="org.jasig.cas.authentication.AuthenticationManagerImpl"> <property name="credentialsToPrincipalResolvers"> <list> <bean class="org.sky.cas.auth.CASCredentialsToPrincipalResolver"> <property name="attributeRepository" ref="attributeRepository" /> </bean> </list> </property> <property name="authenticationHandlers"> <list> <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler" p:httpClient-ref="httpClient" /> <bean class=" org.sky.cas.auth.CASLDAPAuthenticationHandler" p:filter="uid=%u" p:searchBase="o=company,dc=sky,dc=org" p:contextSource-ref="contextSource" /> </list> </property> </bean>
/** * Licensed to Jasig under one or more contributor license * agreements. See the NOTICE file distributed with this work * for additional information regarding copyright ownership. * Jasig licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a * copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.jasig.services.persondir.support.ldap; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.naming.directory.SearchControls; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jasig.cas.util.CASCredentialHelper; import org.jasig.services.persondir.IPersonAttributes; import org.jasig.services.persondir.support.AbstractQueryPersonAttributeDao; import org.jasig.services.persondir.support.CaseInsensitiveAttributeNamedPersonImpl; import org.jasig.services.persondir.support.CaseInsensitiveNamedPersonImpl; import org.jasig.services.persondir.support.QueryType; import org.sky.cas.auth.LdapPersonInfoBean; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.InitializingBean; import org.springframework.ldap.core.AttributesMapper; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.filter.EqualsFilter; import org.springframework.ldap.filter.Filter; import org.springframework.ldap.filter.LikeFilter; import org.springframework.util.Assert; /** * LDAP implementation of {@link org.jasig.services.persondir.IPersonAttributeDao}. * * In the case of multi valued attributes a {@link java.util.List} is set as the value. * * <br> * <br> * Configuration: * <table border="1"> * <tr> * <th align="left">Property</th> * <th align="left">Description</th> * <th align="left">Required</th> * <th align="left">Default</th> * </tr> * <tr> * <td align="right" valign="top">searchControls</td> * <td> * Set the {@link SearchControls} used for executing the LDAP query. * </td> * <td valign="top">No</td> * <td valign="top">Default instance with SUBTREE scope.</td> * </tr> * <tr> * <td align="right" valign="top">baseDN</td> * <td> * The base DistinguishedName to use when executing the query filter. * </td> * <td valign="top">No</td> * <td valign="top">""</td> * </tr> * <tr> * <td align="right" valign="top">contextSource</td> * <td> * A {@link ContextSource} from the Spring-LDAP framework. Provides a DataSource * style object that this DAO can retrieve LDAP connections from. * </td> * <td valign="top">Yes</td> * <td valign="top">null</td> * </tr> * <tr> * <td align="right" valign="top">setReturningAttributes</td> * <td> * If the ldap attributes set in the ldapAttributesToPortalAttributes Map should be copied * into the {@link SearchControls#setReturningAttributes(String[])}. Setting this helps reduce * wire traffic of ldap queries. * </td> * <td valign="top">No</td> * <td valign="top">true</td> * </tr> * <tr> * <td align="right" valign="top">queryType</td> * <td> * How multiple attributes in a query should be concatenated together. The other option is OR. * </td> * <td valign="top">No</td> * <td valign="top">AND</td> * </tr> * </table> * * @author [email protected] * @author Eric Dalquist * @version $Revision$ $Date$ * @since uPortal 2.5 */ public class CASLdapPersonAttributeDao extends AbstractQueryPersonAttributeDao<LogicalFilterWrapper> implements InitializingBean { private static final Pattern QUERY_PLACEHOLDER = Pattern.compile("\\{0\\}"); private final static AttributesMapper MAPPER = new AttributeMapAttributesMapper(); protected final Log logger = LogFactory.getLog(getClass()); /** * The LdapTemplate to use to execute queries on the DirContext */ private LdapTemplate ldapTemplate = null; private String baseDN = ""; private String queryTemplate = null; private ContextSource contextSource = null; private SearchControls searchControls = new SearchControls(); private boolean setReturningAttributes = true; private QueryType queryType = QueryType.AND; public CASLdapPersonAttributeDao() { this.searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); this.searchControls.setReturningObjFlag(false); } /* (non-Javadoc) * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ public void afterPropertiesSet() throws Exception { final Map<String, Set<String>> resultAttributeMapping = this.getResultAttributeMapping(); if (this.setReturningAttributes && resultAttributeMapping != null) { this.searchControls.setReturningAttributes(resultAttributeMapping.keySet().toArray( new String[resultAttributeMapping.size()])); } if (this.contextSource == null) { throw new BeanCreationException("contextSource must be set"); } } /* (non-Javadoc) * @see org.jasig.services.persondir.support.AbstractQueryPersonAttributeDao#appendAttributeToQuery(java.lang.Object, java.lang.String, java.util.List) */ @Override protected LogicalFilterWrapper appendAttributeToQuery(LogicalFilterWrapper queryBuilder, String dataAttribute, List<Object> queryValues) { if (queryBuilder == null) { queryBuilder = new LogicalFilterWrapper(this.queryType); } for (final Object queryValue : queryValues) { String queryValueString = queryValue == null ? null : queryValue.toString(); LdapPersonInfoBean person = new LdapPersonInfoBean(); //person = CASCredentialHelper.getPersoninfoFromCredential(queryValueString); //queryValueString = person.getUsername(); person = CASCredentialHelper.getPersoninfoFromCredential(queryValueString); queryValueString=person.getUsername(); if (StringUtils.isNotBlank(queryValueString)) { final Filter filter; if (!queryValueString.contains("*")) { filter = new EqualsFilter(dataAttribute, queryValueString); } else { filter = new LikeFilter(dataAttribute, queryValueString); } queryBuilder.append(filter); } } return queryBuilder; } /* (non-Javadoc) * @see org.jasig.services.persondir.support.AbstractQueryPersonAttributeDao#getPeopleForQuery(java.lang.Object, java.lang.String) */ @Override protected List<IPersonAttributes> getPeopleForQuery(LogicalFilterWrapper queryBuilder, String queryUserName) { LdapPersonInfoBean ldapPerson = new LdapPersonInfoBean(); ldapPerson = CASCredentialHelper.getPersoninfoFromCredential(queryUserName); final String generatedLdapQuery = queryBuilder.encode(); //If no query is generated return null since the query cannot be run if (StringUtils.isBlank(generatedLdapQuery)) { return null; } //Insert the generated query into the template if it is configured final String ldapQuery; if (this.queryTemplate == null) { ldapQuery = generatedLdapQuery; } else { final Matcher queryMatcher = QUERY_PLACEHOLDER.matcher(this.queryTemplate); ldapQuery = queryMatcher.replaceAll(generatedLdapQuery); } String searchBase = ""; if (ldapPerson.getCompanyid().trim().length() > 0) { searchBase = "o=" + ldapPerson.getCompanyid() + "," + baseDN; } else { searchBase = baseDN; } logger.info("searchBase=====" + searchBase); //Execute the query List<Map<String, List<Object>>> queryResults = new ArrayList<Map<String, List<Object>>>(); try { queryResults = this.ldapTemplate.search(searchBase, ldapQuery, this.searchControls, MAPPER); } catch (Exception e) { logger.error( "search ldap with [searchBase===" + searchBase + "] [ldapQuery====" + ldapQuery + "], caused by: " + e.getMessage(), e); } final List<IPersonAttributes> peopleAttributes = new ArrayList<IPersonAttributes>(queryResults.size()); for (final Map<String, List<Object>> queryResult : queryResults) { IPersonAttributes person; //if (ldapPerson.getUsername() != null) { if (queryUserName != null && queryUserName.trim().length() > 0) { //person = new CaseInsensitiveNamedPersonImpl(ldapPerson.getUsername(), queryResult); person = new CaseInsensitiveNamedPersonImpl(queryUserName, queryResult); } else { //Create the IPersonAttributes doing a best-guess at a userName attribute String userNameAttribute = this.getConfiguredUserNameAttribute(); person = new CaseInsensitiveAttributeNamedPersonImpl(userNameAttribute, queryResult); } peopleAttributes.add(person); } return peopleAttributes; } /** * @see javax.naming.directory.SearchControls#getTimeLimit() * @deprecated Set the property on the {@link SearchControls} and set that via {@link #setSearchControls(SearchControls)} */ @Deprecated public int getTimeLimit() { return this.searchControls.getTimeLimit(); } /** * @see javax.naming.directory.SearchControls#setTimeLimit(int) * @deprecated */ @Deprecated public void setTimeLimit(int ms) { this.searchControls.setTimeLimit(ms); } /** * @return The base distinguished name to use for queries. */ public String getBaseDN() { return this.baseDN; } /** * @param baseDN The base distinguished name to use for queries. */ public void setBaseDN(String baseDN) { if (baseDN == null) { baseDN = ""; } this.baseDN = baseDN; } /** * @return The ContextSource to get DirContext objects for queries from. */ public ContextSource getContextSource() { return this.contextSource; } /** * @param contextSource The ContextSource to get DirContext objects for queries from. */ public synchronized void setContextSource(final ContextSource contextSource) { Assert.notNull(contextSource, "contextSource can not be null"); this.contextSource = contextSource; this.ldapTemplate = new LdapTemplate(this.contextSource); } /** * Sets the LdapTemplate, and thus the ContextSource (implicitly). * * @param ldapTemplate the LdapTemplate to query the LDAP server from. CANNOT be NULL. */ public synchronized void setLdapTemplate(final LdapTemplate ldapTemplate) { Assert.notNull(ldapTemplate, "ldapTemplate cannot be null"); this.ldapTemplate = ldapTemplate; this.contextSource = this.ldapTemplate.getContextSource(); } /** * @return Search controls to use for LDAP queries */ public SearchControls getSearchControls() { return this.searchControls; } /** * @param searchControls Search controls to use for LDAP queries */ public void setSearchControls(SearchControls searchControls) { Assert.notNull(searchControls, "searchControls can not be null"); this.searchControls = searchControls; } /** * @return the queryType */ public QueryType getQueryType() { return queryType; } /** * Type of logical operator to use when joining WHERE clause components * * @param queryType the queryType to set */ public void setQueryType(QueryType queryType) { this.queryType = queryType; } public String getQueryTemplate() { return this.queryTemplate; } /** * Optional wrapper template for the generated part of the query. Use {0} as a placeholder for where the generated query should be inserted. */ public void setQueryTemplate(String queryTemplate) { this.queryTemplate = queryTemplate; } }
String searchBase = ""; if (ldapPerson.getCompanyid().trim().length() > 0) { searchBase = "o=" + ldapPerson.getCompanyid() + "," + baseDN; } else { searchBase = baseDN; } logger.info("searchBase=====" + searchBase);
package org.jasig.cas.util; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.io.StringReader; import java.util.*; import org.jdom.*; import org.jdom.input.SAXBuilder; import org.jdom.xpath.*; import org.sky.cas.auth.LdapPersonInfoBean; import org.xml.sax.InputSource; public class CASCredentialHelper { public final static Log logger = LogFactory.getLog(CASCredentialHelper.class); public static LdapPersonInfoBean getPersoninfoFromCredential(String dnStr) { LdapPersonInfoBean person = new LdapPersonInfoBean(); logger.debug("credential str======" + dnStr); try { if (dnStr != null) { //创建一个新的字符串 String[] p_array = dnStr.split(","); if (p_array != null) { person.setCompanyid(p_array[1]); person.setUsername(p_array[0]); } } } catch (Exception e) { logger.error("get personinfo from DN: [:" + dnStr + "] error caused by: " + e.getMessage(), e); } return person; } public static void main(String[] args) throws Exception { StringBuffer sb = new StringBuffer(); sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); sb.append("<CASCredential>"); sb.append("<result>"); sb.append("<loginid>sys</loginid>"); sb.append("<companyid>401</companyid>"); sb.append("<email>[email protected]</email>"); sb.append("</result>"); sb.append("</CASCredential>"); getPersoninfoFromCredential(sb.toString()); } }
package org.sky.cas.auth; import java.io.Serializable; public class LdapPersonInfoBean implements Serializable { private String companyid = ""; private String username = ""; /** * @return the companyid */ public String getCompanyid() { return companyid; } /** * @param companyid the companyid to set */ public void setCompanyid(String companyid) { this.companyid = companyid; } /** * @return the username */ public String getUsername() { return username; } /** * @param username the username to set */ public void setUsername(String username) { this.username = username; } }
AttributePrincipal principal = (AttributePrincipal) req.getUserPrincipal(); String userName = principal.getName();
Map attributes = principal.getAttributes(); String email = (String) attributes.get("email");
package org.sky.cas.auth; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jasig.cas.authentication.principal.AbstractPersonDirectoryCredentialsToPrincipalResolver; import org.jasig.cas.authentication.principal.Credentials; import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.io.IOException; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; public class CASCredentialsToPrincipalResolver extends AbstractPersonDirectoryCredentialsToPrincipalResolver { public final Log logger = LogFactory.getLog(this.getClass()); protected String extractPrincipalId(final Credentials credentials) { final CASCredential casCredential = (CASCredential) credentials; return buildCompCredential(casCredential.getUsername(), casCredential.getCompanyid()); } /** * Return true if Credentials are UsernamePasswordCredentials, false * otherwise. */ public boolean supports(final Credentials credentials) { return credentials != null && CASCredential.class.isAssignableFrom(credentials.getClass()); } public String buildCompCredential(String loginId, String companyId) { StringBuffer sb = new StringBuffer(); sb.append(loginId).append(","); sb.append(companyId); return sb.toString(); } }注意第23行和 buildCompCredential方法,大家来看这个类原先是继承自 AbstractPersonDirectoryCredentialsToPrincipalResolver 类对吧,如果我们不自定这个类,CAS SSO有一个默认的Resolver,你们知道CAS SSO默认的这个Resolver是怎么写的吗?
package org.sky.cas.auth; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jasig.cas.authentication.principal.AbstractPersonDirectoryCredentialsToPrincipalResolver; import org.jasig.cas.authentication.principal.Credentials; import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.io.IOException; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; public class CASCredentialsToPrincipalResolver extends AbstractPersonDirectoryCredentialsToPrincipalResolver { public final Log logger = LogFactory.getLog(this.getClass()); protected String extractPrincipalId(final Credentials credentials) { final CASCredential casCredential = (CASCredential) credentials; return casCredential.getUsername(); } /** * Return true if Credentials are UsernamePasswordCredentials, false * otherwise. */ }
AttributePrincipal principal = (AttributePrincipal) req.getUserPrincipal(); String userName = principal.getName();
String[] userAttri = userName.split(","); uinfo.setUserName(userAttri[0]); uinfo.setCompanyId(userAttri[1]);
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:sec="http://www.springframework.org/schema/security" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <bean id="authenticationManager" class="org.jasig.cas.authentication.AuthenticationManagerImpl"> <property name="credentialsToPrincipalResolvers"> <list> <bean class="org.sky.cas.auth.CASCredentialsToPrincipalResolver"> <property name="attributeRepository" ref="attributeRepository" /> </bean> </list> </property> <property name="authenticationHandlers"> <list> <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler" p:httpClient-ref="httpClient" /> <bean class=" org.sky.cas.auth.CASLDAPAuthenticationHandler" p:filter="uid=%u" p:searchBase="o=company,dc=sky,dc=org" p:contextSource-ref="contextSource" /> </list> </property> </bean> <!-- ldap datasource --> <bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource"> <property name="password" value="secret" /> <property name="pooled" value="true" /> <property name="url" value="ldap://localhost:389" /> <!--管理员 --> <property name="userDn" value="cn=Manager,dc=sky,dc=org" /> <property name="baseEnvironmentProperties"> <map> <!-- Three seconds is an eternity to users. --> <entry key="com.sun.jndi.ldap.connect.timeout" value="60" /> <entry key="com.sun.jndi.ldap.read.timeout" value="60" /> <entry key="java.naming.security.authentication" value="simple" /> </map> </property> </bean> <sec:user-service id="userDetailsService"> <sec:user name="@@THIS SHOULD BE REPLACED@@" password="notused" authorities="ROLE_ADMIN" /> </sec:user-service> <bean id="attributeRepository" class="org.jasig.services.persondir.support.ldap.CASLdapPersonAttributeDao"> <property name="contextSource" ref="contextSource" /> <property name="baseDN" value="o=company,dc=sky,dc=org" /> <property name="requireAllQueryAttributes" value="true" /> <property name="queryAttributeMapping"> <map> <entry key="username" value="uid" /> </map> </property> <property name="resultAttributeMapping"> <map> <entry key="uid" value="loginid" /> <entry key="mail" value="email" /> </map> </property> </bean> <bean id="serviceRegistryDao" class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl"> <property name="registeredServices"> <list> <bean class="org.jasig.cas.services.RegexRegisteredService"> <property name="id" value="0" /> <property name="name" value="HTTP and IMAP" /> <property name="description" value="Allows HTTP(S) and IMAP(S) protocols" /> <property name="serviceId" value="^(https?|imaps?)://.*" /> <property name="evaluationOrder" value="10000001" /> <property name="ignoreAttributes" value="false" /> <property name="allowedAttributes"> <list> <value>loginid</value> <value>email</value> </list> </property> </bean> </list> </property> </bean> <bean id="auditTrailManager" class="com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager" /> <bean id="healthCheckMonitor" class="org.jasig.cas.monitor.HealthCheckMonitor"> <property name="monitors"> <list> <bean class="org.jasig.cas.monitor.MemoryMonitor" p:freeMemoryWarnThreshold="10" /> <!-- NOTE The following ticket registries support SessionMonitor: * DefaultTicketRegistry * JpaTicketRegistry Remove this monitor if you use an unsupported registry. --> <bean class="org.jasig.cas.monitor.SessionMonitor" p:ticketRegistry-ref="ticketRegistry" p:serviceTicketCountWarnThreshold="5000" p:sessionCountWarnThreshold="100000" /> </list> </property> </bean> </beans>
<bean id="attributeRepository" class="org.jasig.services.persondir.support.ldap.CASLdapPersonAttributeDao"> <property name="contextSource" ref="contextSource" /> <property name="baseDN" value="o=company,dc=sky,dc=org" /> <property name="requireAllQueryAttributes" value="true" /> <property name="queryAttributeMapping"> <map> <entry key="username" value="uid" /> </map> </property> <property name="resultAttributeMapping"> <map> <entry key="uid" value="loginid" /> <entry key="mail" value="email" /> </map> </property> </bean>
Map attributes = principal.getAttributes(); String email = (String) attributes.get("email");
<bean id="serviceRegistryDao" class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl"> <property name="registeredServices"> <list> <bean class="org.jasig.cas.services.RegexRegisteredService"> <property name="id" value="0" /> <property name="name" value="HTTP and IMAP" /> <property name="description" value="Allows HTTP(S) and IMAP(S) protocols" /> <property name="serviceId" value="^(https?|imaps?)://.*" /> <property name="evaluationOrder" value="10000001" /> <property name="ignoreAttributes" value="false" /> <property name="allowedAttributes"> <list> <value>loginid</value> <value>email</value> </list> </property> </bean> </list> </property> </bean>
<property name="allowedAttributes"> <list> <value>loginid</value> <value>email</value> </list> </property>
Map attributes = principal.getAttributes(); String email = (String) attributes.get("email");
<select id="companyid" name="companyid" > <option value="101" selected>上海煤气公司</option> <option value="102" selected>上海自来水厂</option> <option value="103" selected>FBI</option> <option value="104" selected>神盾局</option> </select>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <%@ page session="true"%> <%@ page pageEncoding="utf-8"%> <%@ page contentType="text/html; charset=utf-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> <html> <head> <link href="${pageContext.request.contextPath}/css/login.css" rel="stylesheet" type="text/css" /> <link href="${pageContext.request.contextPath}/css/login_form.css" rel="stylesheet" type="text/css" /> <script language="javascript"> var relativePath="<%=request.getContextPath()%>"; </script> <title>CAS SSO登录</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> </head> <body id="cas"> <div style="text-align: center;"> </div> <form:form method="post" id="fm1" commandName="${commandName}" htmlEscape="true" style="height:300px"> <div class="login_div" id="login"> <table border="0" cellspacing="0" cellpadding="0"> <tr> <td colspan="2" style="border-bottom: 1px solid #e5e9ee;"><img src="${pageContext.request.contextPath}/css/images/login_dot.png" width="24" height="24" hspace="5" align="absbottom" />登录</td> </tr> <tr> <td width="175" class="label"> 用户名:</td> <td width="405"> <c:if test="${empty sessionScope.openIdLocalId}"> <spring:message code="screen.welcome.label.netid.accesskey" var="userNameAccessKey" /> <form:input onblur="refreshOrgList();" id="username" tabindex="1" accesskey="${userNameAccessKey}" path="username"/> </c:if> </td> </tr> <tr> <td class="label">密码:</td> <td><form:password cssClass="required" cssErrorClass="error" id="password" size="25" tabindex="2" path="password" accesskey="${passwordAccessKey}" autocomplete="off" /> </td> </tr> <tr> <td class="label">公司ID:</td> <td> <select id="companyid" name="companyid" > <option value="101" selected>上海煤气公司</option> <option value="102" selected>上海自来水厂</option> <option value="103" selected>FBI</option> <option value="104" selected>神盾局</option> </select> </td> </tr> <tr> <td class="label"></td> <td><font color="red"><form:errors id="msg" class="errors" /> </font></td> </tr> </table> </div> <div class="but_div"> <input type="hidden" name="lt" value="${loginTicket}" /> <input type="hidden" name="execution" value="${flowExecutionKey}" /> <input type="hidden" name="_eventId" value="submit" /> <input name="submit" accesskey="l" class="login_but" value="<spring:message code="screen.welcome.button.login" />" tabindex="4" type="submit" /> <input name="button2" type="reset" class="cancel_but" id="button2" value="取 消" /> </div> </form:form> <div class="loginbottom_div"> <div>Copyright © 红肠啃僵尸 reserved.</div> </div> </body>
Map attributes = principal.getAttributes(); String email = (String) attributes.get("email");
<property name="resultAttributeMapping"> <map> <entry key="uid" value="loginid" /> <entry key="mail" value="email" /> </map> </property>
<!-- return more attributes from attributeRepository start --> <c:if test="${fn:length(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes) > 0}"> <cas:attributes> <c:forEach var="attr" items="${assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes}"> <cas:${fn:escapeXml(attr.key)}>${fn:escapeXml(attr.value)}</cas:${fn:escapeXml(attr.key)}> </c:forEach> </cas:attributes> </c:if> <!-- return more attributes from attributeRepository end -->
<%@ page session="false" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %> <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'> <cas:authenticationSuccess> <cas:user>${fn:escapeXml(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.id)} </cas:user> <!-- return more attributes from attributeRepository start --> <c:if test="${fn:length(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes) > 0}"> <cas:attributes> <c:forEach var="attr" items="${assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes}"> <cas:${fn:escapeXml(attr.key)}>${fn:escapeXml(attr.value)}</cas:${fn:escapeXml(attr.key)}> </c:forEach> </cas:attributes> </c:if> <!-- return more attributes from attributeRepository end --> <c:if test="${not empty pgtIou}"> <cas:proxyGrantingTicket>${pgtIou}</cas:proxyGrantingTicket> </c:if> <c:if test="${fn:length(assertion.chainedAuthentications) > 1}"> <cas:proxies> <c:forEach var="proxy" items="${assertion.chainedAuthentications}" varStatus="loopStatus" begin="0" end="${fn:length(assertion.chainedAuthentications)-2}" step="1"> <cas:proxy>${fn:escapeXml(proxy.principal.id)}</cas:proxy> </c:forEach> </cas:proxies> </c:if> </cas:authenticationSuccess> </cas:serviceResponse>
package org.sky.framework.session; import java.io.Serializable; public class UserSession implements Serializable { private String companyId = ""; private String userName = ""; private String userEmail = ""; public String getCompanyId() { return companyId; } public void setCompanyId(String companyId) { this.companyId = companyId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserEmail() { return userEmail; } public void setUserEmail(String userEmail) { this.userEmail = userEmail; } }
package org.sky.framework.session; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.ServletContext; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; public class AppSessionListener implements HttpSessionListener { protected Logger logger = LoggerFactory.getLogger(this.getClass()); @Override public void sessionCreated(HttpSessionEvent se) { HttpSession session = null; try { session = se.getSession(); // get value ServletContext context = session.getServletContext(); String timeoutValue = context.getInitParameter("sessionTimeout"); int timeout = Integer.valueOf(timeoutValue); // set value session.setMaxInactiveInterval(timeout); logger.info(">>>>>>session max inactive interval has been set to " + timeout + " seconds."); } catch (Exception ex) { ex.printStackTrace(); } } @Override public void sessionDestroyed(HttpSessionEvent arg0) { // TODO Auto-generated method stub } }
package org.sky.framework.session; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import org.jasig.cas.client.authentication.AttributePrincipal; import org.jasig.cas.client.util.AssertionHolder; import org.jasig.cas.client.validation.Assertion; import org.sky.util.WebConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SampleSSOSessionFilter implements Filter { protected Logger logger = LoggerFactory.getLogger(this.getClass()); private String excluded; private static final String EXCLUDE = "exclude"; private boolean no_init = true; private ServletContext context = null; private FilterConfig config; String url = ""; String actionName = ""; public void setFilterConfig(FilterConfig paramFilterConfig) { if (this.no_init) { this.no_init = false; this.config = paramFilterConfig; if ((this.excluded = paramFilterConfig.getInitParameter("exclude")) != null) this.excluded += ","; } } private String getActionName(String actionPath) { logger.debug("filter actionPath====" + actionPath); StringBuffer actionName = new StringBuffer(); try { int begin = actionPath.lastIndexOf("/"); if (begin >= 0) { actionName.append(actionPath.substring(begin, actionPath.length())); } } catch (Exception e) { } return actionName.toString(); } private boolean excluded(String paramString) { // logger.info("paramString====" + paramString); // logger.info("excluded====" + this.excluded); // logger.info(this.excluded.indexOf(paramString + ",")); if ((paramString == null) || (this.excluded == null)) return false; return (this.excluded.indexOf(paramString + ",") >= 0); } @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain arg2) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; UserSession uinfo = new UserSession(); HttpSession se = req.getSession(); url = req.getRequestURI(); actionName = getActionName(url); //actionName = url; logger.debug(">>>>>>>>>>>>>>>>>>>>SampleSSOSessionFilter: request actionname" + actionName); if (!excluded(actionName)) { try { uinfo = (UserSession) se.getAttribute(WebConstants.USER_SESSION_OBJECT); AttributePrincipal principal = (AttributePrincipal) req.getUserPrincipal(); String userName = principal.getName(); logger.info("userName: " + userName); if (userName != null && userName.length() > 0 && uinfo == null) { Map attributes = principal.getAttributes(); String email = (String) attributes.get("email"); uinfo = new UserSession(); String[] userAttri = userName.split(","); uinfo.setUserName(userAttri[0]); uinfo.setCompanyId(userAttri[1]); uinfo.setUserEmail(email); se.setAttribute(WebConstants.USER_SESSION_OBJECT, uinfo); } } catch (Exception e) { logger.error("SampleSSOSessionFilter error:" + e.getMessage(), e); resp.sendRedirect(req.getContextPath() + "/syserror.jsp"); return; } } else { arg2.doFilter(request, response); return; } try { arg2.doFilter(request, response); return; } catch (Exception e) { logger.error("SampleSSOSessionFilter fault: " + e.getMessage(), e); } } @Override public void init(FilterConfig config) throws ServletException { // TODO Auto-generated method stub this.config = config; if ((this.excluded = config.getInitParameter("exclude")) != null) this.excluded += ","; this.no_init = false; } }
<filter> <filter-name>SampleSSOSessionFilter</filter-name> <filter-class>org.sky.framework.session.SampleSSOSessionFilter</filter-class> <init-param> <param-name>exclude</param-name> <param-value>/syserror.jsp </param-value> </init-param> </filter> <filter-mapping> <filter-name>SampleSSOSessionFilter</filter-name> <url-pattern>*</url-pattern> </filter-mapping>
uinfo = (UserSession) se.getAttribute(WebConstants.USER_SESSION_OBJECT); AttributePrincipal principal = (AttributePrincipal) req.getUserPrincipal(); String userName = principal.getName(); logger.info("userName: " + userName); if (userName != null && userName.length() > 0 && uinfo == null) { Map attributes = principal.getAttributes(); String email = (String) attributes.get("email"); uinfo = new UserSession(); String[] userAttri = userName.split(","); uinfo.setUserName(userAttri[0]); uinfo.setCompanyId(userAttri[1]); uinfo.setUserEmail(email); se.setAttribute(WebConstants.USER_SESSION_OBJECT, uinfo); }
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ page import="org.sky.framework.session.UserSession, org.sky.util.WebConstants" %> <% UserSession us=(UserSession)session.getAttribute(WebConstants.USER_SESSION_OBJECT); String uname=us.getUserName(); String email=us.getUserEmail(); String companyId=us.getCompanyId(); %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>cas sample site1</title> </head> <body> <h1>cas sample site1 Hello: <%=uname%>(<%=email%>) u are@Company: <%=companyId%></h1> </p> <a href="http://localhost:8080/cas-sample-site2/index.jsp">cas-sample-site2</a> </br> <a href="http://localhost:8080/cas-server/logout">退出</a> </body> </html>
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ page import="org.sky.framework.session.UserSession, org.sky.util.WebConstants" %> <% UserSession us=(UserSession)session.getAttribute(WebConstants.USER_SESSION_OBJECT); String uname=us.getUserName(); String email=us.getUserEmail(); String companyId=us.getCompanyId(); %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>cas sample site2</title> </head> <body> <h1>cas sample site2 Hello: <%=uname%>(<%=email%>) u are@Company: <%=companyId%></h1> <a href="http://localhost:8080/cas-sample-site1/index.jsp">cas-sample-site1</a> </br> <a href="http://localhost:8080/cas-server/logout">退出</a> </body> </html>
dn: dc=sky,dc=org dc: sky objectClass: top objectClass: domain dn: o=company,dc=sky,dc=org objectClass: organization o: company dn: ou=members,o=company,dc=sky,dc=org objectClass: organizationalUnit ou: members dn: cn=user1,ou=members,o=company,dc=sky,dc=org sn: user1 cn: user1 userPassword: aaaaaa objectClass: organizationalPerson dn: cn=user2,ou=members,o=company,dc=sky,dc=org sn: user2 cn: user2 userPassword: abcdefg objectClass: organizationalPerson dn: uid=mk,ou=members,o=company,dc=sky,dc=org objectClass: posixAccount objectClass: top objectClass: inetOrgPerson gidNumber: 0 givenName: Yuan sn: MingKai displayName: YuanMingKai uid: mk homeDirectory: e:\user mail: [email protected] cn: YuanMingKai uidNumber: 13599 userPassword: {SHA}96niR3fsIyEsVNejULxb6lR3/bs= dn: o=101,o=company,dc=sky,dc=org o: 101 objectClass: organization dn: o=102,o=company,dc=sky,dc=org o: 102 objectClass: organization dn: o=103,o=company,dc=sky,dc=org o: 103 objectClass: organization dn: o=104,o=company,dc=sky,dc=org o: 104 objectClass: organization dn: uid=marious,o=101,o=company,dc=sky,dc=org objectClass: posixAccount objectClass: top objectClass: inetOrgPerson gidNumber: 0 givenName: Wang sn: LiMing displayName: WangLiMing uid: marious homeDirectory: d:\ cn: WangLiMing uidNumber: 47967 userPassword: {SHA}96niR3fsIyEsVNejULxb6lR3/bs= mail: [email protected] dn: uid=sky,o=101,o=company,dc=sky,dc=org objectClass: posixAccount objectClass: top objectClass: inetOrgPerson gidNumber: 0 givenName: Yuan sn: Tao displayName: YuanTao uid: sky homeDirectory: d:\ cn: YuanTao uidNumber: 26422 userPassword: {SHA}96niR3fsIyEsVNejULxb6lR3/bs= mail: [email protected] dn: uid=jason,o=102,o=company,dc=sky,dc=org objectClass: posixAccount objectClass: top objectClass: inetOrgPerson gidNumber: 0 givenName: zhang sn: lei displayName: zhanglei uid: jason homeDirectory: d:\ cn: zhanglei uidNumber: 62360 userPassword: {SHA}96niR3fsIyEsVNejULxb6lR3/bs= mail: [email protected] dn: uid=andy.li,o=103,o=company,dc=sky,dc=org objectClass: posixAccount objectClass: top objectClass: inetOrgPerson gidNumber: 0 givenName: Li sn: Jun displayName: LiJun uid: andy.li homeDirectory: d:\ cn: LiJun uidNumber: 51204 userPassword: {SHA}96niR3fsIyEsVNejULxb6lR3/bs= mail: [email protected] dn: uid=pitt,o=104,o=company,dc=sky,dc=org objectClass: posixAccount objectClass: top objectClass: inetOrgPerson gidNumber: 0 givenName: Brad sn: Pitt displayName: Brad Pitt uid: pitt homeDirectory: d:\ cn: Brad Pitt uidNumber: 64650 userPassword: {SHA}96niR3fsIyEsVNejULxb6lR3/bs= mail: [email protected]
<select id="companyid" name="companyid" > <option value="101" selected>上海煤气公司</option> <option value="102" selected>上海自来水厂</option> <option value="103" selected>FBI</option> <option value="104" selected>神盾局</option> </select>是102,说明我们的传值传对了。