Cobbler Multi -System Automation Installation


Because the company has many internal systems and many account systems, it is necessary to realize unified account account login to different systems. LDAP is now used to manage account numbers.
Shiro also provides LDAP support, combined with online information, write the following content.

  1. Jeesite The existing account system. Users to maintain the email address and correspond to the email address stored in LDAP
  2. Custom LDAPAUTHORIZINGREALM inherit the JNDILDAPREALM class, rewriting the method inside.
  3. Add custom Realm in Spring-Context-SHIRO.XML


import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.naming.AuthenticationNotSupportedException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.ldap.LdapContext;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.ldap.UnsupportedAuthenticationMechanismException;
import org.apache.shiro.realm.ldap.JndiLdapRealm;
import org.apache.shiro.realm.ldap.LdapContextFactory;
import org.apache.shiro.realm.ldap.LdapUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

 * LdapRealm
 * @author huangkai
public class LdapAuthorizingRealm extends JndiLdapRealm{
	private Logger logger = LoggerFactory.getLogger(getClass());
	private SystemService systemService;
	private String rootDN;

    public String getRootDN() {
        return rootDN;

    public void setRootDN(String rootDN) {
        this.rootDN = rootDN;

	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken){
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		// check login verification code
		if (LoginController.isValidateCodeLogin(token.getUsername(), false, false)){
			Session session = UserUtils.getSession();
			String code = (String)session.getAttribute(ValidateCodeServlet.VALIDATE_CODE);
			if (token.getCaptcha() == null || !token.getCaptcha().toUpperCase().equals(code)){
				throw new AuthenticationException("msg: verification code error, please try it." ");
		AuthenticationInfo info;
        try {
            info = queryForAuthenticationInfo(token, getContextFactory());
        } catch (AuthenticationNotSupportedException e) {
            String msg = "msg:Unsupported configured authentication mechanism";
            throw new UnsupportedAuthenticationMechanismException(msg, e);
        } catch (javax.naming.AuthenticationException e) {
            String msg = "msg:LDAP authentication failed.";
            throw new AuthenticationException(msg, e);
        } catch (NamingException e) {
            String msg = "msg:LDAP naming error while attempting to authenticate user.";
            throw new AuthenticationException(msg, e);
        } catch (UnknownAccountException e) {
            String msg = "MSG: The account does not exist!";
            throw new UnknownAccountException(msg, e);
        } catch (IncorrectCredentialsException e) {
            String msg = "msg: password error";
            throw new IncorrectCredentialsException(msg, e);

        return info;
      * Connect LDAP to query whether the user information exists 
      * <p> 
      * 1. Get the login name and password from the page. Note that the login name and password here were not used at the beginning. 
      * 2. First anonymous binding to the LDAP server. If the LDAP server does not enable anonymous binding, it will generally provide a default user. Use this user for binding. 
      * 3. The login name entered before is useful here. When the previous step is successful, a search needs to be performed, and the Filter is constructed with the login name, such as: "cn =* (xn607659)". 
      * After the search is executed, you need to judge the results. If you only return one Entry, this is the Entry containing the user information, you can get the DN of the Entry, and use it later. 
      * If there are more than one or no return, it means that the user name input is wrong, and you should quit verification and return the error message. 
      * 4. If this step can be performed, it means that the corresponding users are used, and the DN of the entry information where the user information is located in the previous step. Essence 
      * 5. After the previous step is performed, the main process of verification is over. If it can be successfully bound, it means that the verification is successful. If it does not work, the password error information should be returned. 
      * These 5 big steps are a "two -binding" verification method based on LDAP 
      * @param token 
      * @param ldapcontextFactory 
      * @Return 
      * @throws namingexception 
    protected AuthenticationInfo queryForAuthenticationInfo(
            AuthenticationToken authcToken, LdapContextFactory ldapContextFactory)
            throws NamingException {
    	UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        Object principal = token.getPrincipal();// The user name entered
        Object credentials = token.getCredentials();// The password input
        String userName = principal.toString();
        String password = new String((char[]) credentials);

        LdapContext systemCtx = null;
        LdapContext ctx = null;
        try {
            // Use the system configured user to connect LDAP
            systemCtx = ldapContextFactory.getSystemLdapContext();

            SearchControls constraints = new SearchControls();
            constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);// The search range includes subtree
            NamingEnumeration<SearchResult> results =, "cn=" + principal, constraints);
            if (results != null && !results.hasMore()) {
                throw new UnknownAccountException();
            } else {
            	String mail=null;
                while (results.hasMore()) {
                    SearchResult si = (SearchResult);
                    principal = si.getName() + "," + rootDN;
                    mail= si.getAttributes().get("mail").get(0).toString();
      "DN=[" + principal + "]");
                try {
                    // Connect LDAP according to the inquiries with the input password, the user password is correct to connect
                    ctx = ldapContextFactory.getLdapContext(principal, credentials);
                    dealUser(userName, password);
                } catch (NamingException e) {
                    throw new IncorrectCredentialsException();
                // Check the user name password
                	User user = getSystemService().getUserByMail(mail);
                	if (user != null) {
            			if (Global.NO.equals(user.getLoginFlag())){
            				throw new AuthenticationException("MSG: The account is prohibited to log in.");
            			byte[] salt = Encodes.decodeHex(user.getPassword().substring(0,16));
            			return new SimpleAuthenticationInfo(new Principal(user, token.isMobileLogin()), 
            					user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName());
            		} else {
            			throw new AuthenticationException("msg:"+mail+"No account corresponding to the mailbox");
                	throw new AuthenticationException("msg:"+"LDAP does not configure the user's mailbox");
        } finally {
            // Turn off the connection 

 twenty two#   /** 
 * Authorized query recovery function, calling for authentication, but calling when there is no user authorized information in the cache 
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		Principal principal = (Principal) getAvailablePrincipal(principals);
		// Get the user currently logged in
		if (!Global.TRUE.equals(Global.getConfig("user.multiAccountLogin"))){
			Collection<Session> sessions = getSystemService().getSessionDao().getActiveSessions(true, principal, UserUtils.getSession());
			if (sessions.size() > 0){
				// If you log in and come in, kick out the online user
				if (UserUtils.getSubject().isAuthenticated()){
					for (Session session : sessions){
				// Remember what I came in, and the current user has logged in, then exit the current user prompt message.
					throw new AuthenticationException("MSG: The account has been logged in other places, please log in again.");
		User user = getSystemService().getUserByLoginName(principal.getLoginName());
		if (user != null) {
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
			List<Menu> list = UserUtils.getMenuList();
			for (Menu menu : list){
				if (StringUtils.isNotBlank(menu.getPermission())){
					// Add permissions based on Permit
					for (String permission : StringUtils.split(menu.getPermission(),",")){
			// Add user permissions
			// Add user role information
			for (Role role : user.getRoleList()){
			// Update login IP and time
			// Record login log
			LogUtils.saveLog(Servlets.getRequest(), "System login");
			return info;
		} else {
			return null;
      * Save the user found by LDAP to the sys_user table 
      * @param username 
    private void dealUser(String userName, String password) {
        if (StringUtils.isEmpty(userName)) {
        //TO DO...
      * Obtaining permissions code 
      * @param username 
      * @Return 
    private Map<String, Set<String>> getAuthorizationInfo(String username) {

        Map<String, Set<String>> authorizationMap = new HashMap<String, Set<String>>();
        Set<String> codeSet = new HashSet<String>();

        Session session = SecurityUtils.getSubject().getSession();
        // Query user permissions of the database

        authorizationMap.put("permissions", codeSet);
        session.setAttribute("permissions", codeSet);
        logger.debug("The current login account: {} permissions collection: {}", username, codeSet);
        return authorizationMap;

 * Get the system business object 
	public SystemService getSystemService() {
		if (systemService == null){
			systemService = SpringContextHolder.getBean(SystemService.class);
		return systemService;

<!-Define SHIRO safety management configuration-> 
 <bean id = "securityManager" class = "org.apache.shiro.web.mgt.defaultWebSecurityManager"> 
 <!-<Property name = "Realm" Ref = "SystemAutHorizingRealm" />-> 
 <property name = "sessionManager" ref = "sessionManager" /> /> 
 <propoperty name = "cacheManager" ref = "shirocacheManager" /> /> 
 <property name = "authenticator" ref = "authenticator"/> 
 <property name = "realms"> 
                 <ref bean = "systemmauthorizingrealm" /> 
                 <ref bean = "ldapauthorizingRealm" /> 
 <bean id = "authenticator" class = "org.apache.shiro.authc.pam.modularRealRealMauthenticator"> 
         <property name = "authenticationStrategy"> 
             <bean class = "org.apache.shiro.authc.pam.firtSuccessfulstrategy"> </Bean> 
 <!-Rewilling LDAP certification here ROOTDN is the root directory of the employee of the search company-> 
     <bean id = "ldapaultHorizingRealm" class = ""> 
         <propoperty name = "rootdn" value = "ou = ****, dc = ****, dc = com"/> 
         <property name = "userdntemplate" value = "{0}"/> 
         <propoperty name = "contextFactory" ref = "contextFactory"/>/> 

     <!-Configure the LDAP path and configure a default user and password-> 
     <bean id = "contextFactory" class = "org.apache.shiro.realm.ldap.jndildapcontextFactory">> 
         <propoperty name = "url" value = "ldap: //***.***.****/"/> 
         <propoperty name = "SystemUsername" Value = "CN = *****, OU = Operating Platform Product Line, OU = Product R & D Center, OU = ****, DC = ****, DC = Com"/ " 
         <propoperty name = "SystemPassword" value = "******"/> 

Shiro certification strategy, if there are multiple Realm, how can it be regarded as a successful certification, which requires the certification strategy.
AuthenticationStrategy interface default implementation:

  • firstSuccessFulstrategy: As long as a realm verification is successful, only the first Realm authentication authentication information is returned. Other ignition;
  • AtleastoneSuccessfulStrategy: As long as there is a Realm verification success, unlike FirstSuccessFulstrategy, it will return to all Realm authentication certification information;
  • AllSuccessFulstrategy: All Realm verification is successful, and the authentication information of successful authentication is returned. If there is a failure, it will fail.
  • ModularrealMauthenticator default is the AsleastoneSuccessfulstrategy strategy

  1. shiro-multi-realm verification
  2. Shiro uses LDAP certification


Related Posts

Latex Reference Form, Photos, and Formula Automatically add Table, Fig, EQU

Talk about Vue component welkin

Those Python libraries that have been underestimated, see how many have you used? Wang

10.31 NOIP simulation race (Morning)

Cobbler Multi -System Automation Installation

Random Posts

Android animation Frameanimation (frame animation) AnimationDrawable

Detailed explanation of the implementation of Call, Apply, and Bind in JS (source code implementation)

Go Slice Detailed Explanation of Goang Slice

linux simply read and write a file