tomcat 安全机制解析

在tomcat中利用领域对象realm进行验证,Realm中的主要方法为authenticate(),通常realm与context容器相关联

   public Principal authenticate(String username, String credentials) {

        GenericPrincipal principal = principals.get(username); //从hashmap中获取该用户对应的验证实体对象

        boolean validated;
        if (principal == null) { //没有验证类对象说明没有改用户,直接返回 
            validated = false;
        } else {
            validated = compareCredentials(credentials, principal.getPassword());//将用户输入的密码,与服务端密码进行比对
        }

        if (validated) {
            if (log.isDebugEnabled())
                log.debug(sm.getString("memoryRealm.authenticateSuccess", username));
            return (principal);
        } else {
            if (log.isDebugEnabled())
                log.debug(sm.getString("memoryRealm.authenticateFailure", username));
            return (null);
        }

    }
 protected boolean compareCredentials(String userCredentials,
            String serverCredentials) {

        if (serverCredentials == null) {
            return false;
        }

        if (hasMessageDigest()) {
            // Some directories and databases prefix the password with the hash
            // type. The string is in a format compatible with Base64.encode not
            // the normal hex encoding of the digest
            if (serverCredentials.startsWith("{MD5}") ||
                    serverCredentials.startsWith("{SHA}")) {
                // Server is storing digested passwords with a prefix indicating
                // the digest type
                String serverDigest = serverCredentials.substring(5);
                String userDigest;
                synchronized (this) {
                    md.reset();
                    md.update(userCredentials.getBytes(B2CConverter.ISO_8859_1));
                    userDigest = Base64.encodeBase64String(md.digest());
                }
                return userDigest.equals(serverDigest);

            } else if (serverCredentials.startsWith("{SSHA}")) {
                // Server is storing digested passwords with a prefix indicating
                // the digest type and the salt used when creating that digest

                String serverDigestPlusSalt = serverCredentials.substring(6);

                // Need to convert the salt to bytes to apply it to the user's
                // digested password.
                byte[] serverDigestPlusSaltBytes =
                        Base64.decodeBase64(serverDigestPlusSalt);
                final int saltPos = 20;
                byte[] serverDigestBytes = new byte[saltPos];
                System.arraycopy(serverDigestPlusSaltBytes, 0,
                        serverDigestBytes, 0, saltPos);

                // Generate the digested form of the user provided password
                // using the salt
                byte[] userDigestBytes;
                synchronized (this) {
                    md.reset(); 
                    // User provided password
                    md.update(userCredentials.getBytes(B2CConverter.ISO_8859_1));
                    // Add the salt
                    md.update(serverDigestPlusSaltBytes, saltPos,
                            serverDigestPlusSaltBytes.length - saltPos);
                    userDigestBytes = md.digest();
                }

                return Arrays.equals(userDigestBytes, serverDigestBytes);

            } else {
                // Hex hashes should be compared case-insensitively
                String userDigest = digest(userCredentials);
                return serverCredentials.equalsIgnoreCase(userDigest);
            }
        } else {
            // No digests, compare directly
            return serverCredentials.equals(userCredentials);
        }
    }

 

realm中的属性有

 /**
     * The set of valid Principals for this Realm, keyed by user name.
* 利用hashmap保存 验证类对象
*/ private Map<String,GenericPrincipal> principals = new HashMap<String,GenericPrincipal>();

GenericPrincipal中的属性主要有username,password以及该用户所对应的权限

  public GenericPrincipal(String name, String password, List<String> roles) {
        this(name, password, roles, null);
    }

主要方法为

 /**
     * Does the user represented by this Principal possess the specified role?
     * 判断用户是否具有某个权限,并利用二分查找进行搜索
     * @param role Role to be tested
     */
    public boolean hasRole(String role) {

        if("*".equals(role)) // Special 2.4 role meaning everyone
            return true;
        if (role == null)
            return (false);
        return (Arrays.binarySearch(roles, role) >= 0);

    }

二分查找方法为:

  // Like public version, but without range checks.
    private static int binarySearch0(Object[] a, int fromIndex, int toIndex,
                                     Object key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            Comparable midVal = (Comparable)a[mid];
            int cmp = midVal.compareTo(key);

            if (cmp < 0)
                low = mid + 1;
            else if (cmp > 0)
                high = mid - 1;
            else
                return mid; // key found
        }
        return -(low + 1);  // key not found.
    }

 

posted @ 2015-10-12 22:38  程序猿进化之路  阅读(353)  评论(0)    收藏  举报