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. }

浙公网安备 33010602011771号