How Tomcat works 10: Security類
1. 概述: WebApp的資源的訪問限制可以通過web.xml檔案來支撐。Servlet容器可以通過叫做Authenticator valve類來支援。Authenticator valve會呼叫context's realms的authenticate方法校驗user 2. Realm類 (1)一個Realm通常附屬於一個context, 一個container只能有一個realm【container.setRealm(realm)】 (2)預設下,Tomcat的預設認證資訊儲存在tomcat-users.xml中。當然也可以使用別的認證資源,如database (3)Realm介面包含四個overload方法
public interface Realm { public Principal authenticate(String username, String credentials); public Principal authenticate(String username, byte[] credentials); public Principal authenticate(String username, String digest, String nonce, String nc, String cnonce, String qop, String realm, String md5a2); public Principal authenticate(X509Certificate cters[]); public boolean hasRole(Principal principal, String role); }
3. GenericPrincipal: (1)是Principal介面的實現類
public class GenericPrincipal implements Principal { protected Realm realm; private String name; private String password; private String[] roles; public GenericPrincipal(Realm realm, String name, String password) { this(realm, name, password, null); } public GenericPrincipal(Realm realm, String name, String password, List<?> roles) { super(); this.realm = realm; this.name = name; this.password = password; if(roles != null) { this.roles = new String[roles.size()]; this.roles = (String[])roles.toArray(this.roles); if(this.roles.length>0) { Arrays.sort(this.roles); } } } public boolean hasRole(String role) { if("*".equals(role)) { return true; } if(role == null) { return false; } return (Arrays.binarySearch(roles, role)>=0); } @Override public String getName() { return name; } }
4. LoginConfig類 (1)包含了realm name和authentication方法authentication name必須是其中之一:BASIC,DIGEST,FORM,CLIENT-CERT (2)部署過程中,Tomcat啟動時讀取web.xml檔案,若包含了login-config元素, tomcat將建立以惡LoginConfig物件 5. Authenticator介面 (1)代表一個認證介面,沒有任何方法,僅僅是一個標記 (2)UML 6. Bootstrap: 在啟動過程中,使用context.getLoginConfig()->然後使用反射查詢相應的authenticator,新增對應的valve到pipeline
private synchronized void authenticatorConfig() {
SecurityConstraint constraints[] = context.findConstraints();
if ((constraints == null) || (constraints.length == 0))
return;
LoginConfig loginConfig = context.getLoginConfig();
if (loginConfig == null) {
loginConfig = new LoginConfig("NONE", null, null, null);
context.setLoginConfig(loginConfig);
}
// Has an authenticator been configured already?
Pipeline pipeline = ((StandardContext) context).getPipeline();
if (pipeline != null) {
Valve basic = pipeline.getBasic();
if ((basic != null) && (basic instanceof Authenticator))
return;
Valve valves[] = pipeline.getValves();
for (int i = 0; i < valves.length; i++) {
if (valves[i] instanceof Authenticator)
return;
}
} else { // no Pipeline, cannot install authenticator valve
return;
}
// Has a Realm been configured for us to authenticate against?
if (context.getRealm() == null) {
return;
}
// Identify the class name of the Valve we should configure
String authenticatorName = "org.apache.catalina.authenticator.BasicAuthenticator";
// Instantiate and install an Authenticator of the requested class
Valve authenticator = null;
try {
Class authenticatorClass = Class.forName(authenticatorName);
authenticator = (Valve) authenticatorClass.newInstance();
((StandardContext) context).addValve(authenticator);
System.out.println("Added authenticator valve to Context");
} catch (Throwable t) {
}
}