[Tomcat源码系列] 扩展

一、    Realm/ HTTP认证

1)Realm

Realm提供了Web认证用户和角色信息的存储机制,如下是Tomcat关于Realm的说明
A Realm is a read-only facade for an underlying security realm used to authenticate individual users, and identify the security roles associated with those users. Realms can be attached at any Container level, but will typically only be attached to a Context, or higher level, Container.

我们看看Realm的接口定义

public interface Realm {
    public Container getContainer();
    public void setContainer(Container container);
    public String getInfo();
    public void addPropertyChangeListener(PropertyChangeListener listener);
    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 certs[]);
    public void backgroundProcess();
    public SecurityConstraint [] findSecurityConstraints(Request request,
    public boolean hasResourcePermission(Request request,
                                         Response response,
                                         SecurityConstraint [] constraint,
                                         Context context)
        throws IOException;
    public boolean hasRole(Principal principal, String role);
    public boolean hasUserDataPermission(Request request,
                                         Response response,
                                         SecurityConstraint []constraint)
        throws IOException;
    public void removePropertyChangeListener(PropertyChangeListener listener);
}
 

   Tomcat提供了多种的Realm实现,实现代码比较简单

  • org.apache.catalina.realm.DataSourceRealm:Implmentation of Realm that works with any JDBC JNDI DataSource.See the JDBCRealm.howto for more details on how to set up the database and for configuration options
  • org.apache.catalina.realm.JAASRealm:Implmentation of Realm that authenticates users via the Java Authentication and Authorization Service (JAAS).
  • org.apache.catalina.realm.JDBCRealm:Implmentation of <b>Realm</b> that works with any JDBC supported database. See the JDBCRealm.howto for more details on how to set up the database and for configuration options.
  • org.apache.catalina.realm.JNDIRealm:Implementation of <strong>Realm</strong> that works with a directory server accessed via the Java Naming and Directory Interface (JNDI) APIs.
  • org.apache.catalina.realm.MemoryRealm:Simple implementation of <b>Realm</b> that reads an XML file to configure the valid users, passwords, and roles.
  • org.apache.catalina.realm.UserDatabaseRealm:Implementation of Realm that is based on an implementation of UserDatabase made available through the global JNDI resources configured for this instance of Catalina.(通过UserDatabase接口来获取认证信息,默认配置这个,见{tomcat}/conf/tomcat-users.xml)

2)HTTP认证  关于HTTP认证可参见《HTTP认证及其在Web平台中的实现》,Tomcat通过Realm实现HTTP认证用户/角色信息的存储。Tomcat的HTTP认证实现以Valve的方式提供的(见之前关于pipeline的说明,需要注意的是,这个Valve不需要显式地配置,默认ContextConfig会根据web.xml设置的信息自动注册一个认证实现),每种实现会实现org.apache.catalina.Authenticator接口(空接口)

public interface Authenticator {
}

   默认Tomcat提供了如下的实现,代码比较简单,可同时参见Realm的实现

  • BASIC=org.apache.catalina.authenticator.BasicAuthenticator
  • CLIENT-CERT=org.apache.catalina.authenticator.SSLAuthenticator
  • DIGEST=org.apache.catalina.authenticator.DigestAuthenticator
  • FORM=org.apache.catalina.authenticator.FormAuthenticator
  • NONE=org.apache.catalina.authenticator.NonLoginAuthenticator

如下是tomcat默认提供的manager的web.xml中关于HTTP认证部分的配置

<security-constraint>
    <web-resource-collection>
      <web-resource-name>HTMLManger and Manager command</web-resource-name>
      <url-pattern>/jmxproxy/*</url-pattern>
      <url-pattern>/html/*</url-pattern>
      <url-pattern>/list</url-pattern>
      <url-pattern>/expire</url-pattern>
      <url-pattern>/sessions</url-pattern>
      <url-pattern>/start</url-pattern>
      <url-pattern>/stop</url-pattern>
      <url-pattern>/install</url-pattern>
      <url-pattern>/remove</url-pattern>
      <url-pattern>/deploy</url-pattern>
      <url-pattern>/undeploy</url-pattern>
      <url-pattern>/reload</url-pattern>
      <url-pattern>/save</url-pattern>
      <url-pattern>/serverinfo</url-pattern>
      <url-pattern>/status/*</url-pattern>
      <url-pattern>/roles</url-pattern>
      <url-pattern>/resources</url-pattern>
      <url-pattern>/findleaks</url-pattern>
    </web-resource-collection>
    <auth-constraint>
       <!-- NOTE:  This role is not present in the default users file -->
       <role-name>manager</role-name>
    </auth-constraint>
  </security-constraint>

  <!-- Define the Login Configuration for this Application -->
  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>Tomcat Manager Application</realm-name>
  </login-config>

  <!-- Security roles referenced by this web application -->
  <security-role>
    <description>
      The role that is required to log in to the Manager Application
    </description>
    <role-name>manager</role-name>
  </security-role>

二、    Manager/Cluster

1.Manager

Manager接口实现了对Session的管理,看看Tomcat中关于Manager的定义
A Manager manages the pool of Sessions that are associated with a particular Container. Different Manager implementations may support value-added features such as the persistent storage of session data,as well as migrating sessions for distributable web applications.

org.apache.catalina.session.StandardManager是默认的Manager实现,在内存中维持Session信息,并支持简单地将 Session持久化到文件中,以支持在Tomcat重启后Session信息不会全部丢失(注意,只有通过正确的shutdown,Session信息才会被正确持久化)我们可以通过扩展Manager来自定制对Session的管理(譬如,我们可以扩展使用memcached来存储session数据),除StandardManager,Tomcat还提供了如下的Session实现

  • org.apache.catalina.session.PersistentManager:支持将不活跃的Session数据持久化,只维持部分Session信息在内存,一方面支持服务重启而Session不丢失,一方面支持错误恢复,即使服务非正常重启也能够保证Session信息不丢失,另一方面只须要在内存中维持部分的Session信息。其中数据的持久化是一种策略,支持文件、数据库等方式的持久化,关于持久化策略,具体参见org.apache.catalina.Store及其实现org.apache.catalina.session.FileStore和org.apache.catalina.session.JDBCStore。我们可以通过使用共享文件/数据库的方式, PersistentManager+FileStore/ JDBCStore来实现Session数据的集群,需要注意的是,PersistentManager只会当Session Idle时才会持久化Session数据,因此不是实时复制的
  • org.apache.catalina.ha.session.SimpleTcpReplicationManager:ha Session实现,使用全复制的方式,在请求处理完毕之后,如果Session有变化,则将整个Session数据复制给其他的集群节点
  • org.apache.catalina.ha.session.DeltaManager;ha Session实现,采用只复制变更部分的方式,在请求处理完毕之后,将Session有变更的数据部分复制给其他的节点
  • org.apache.catalina.ha.session.BackupManager:ha Session实现,与DeltaManager复制方式一样,但不是复制给所有节点,而是只复制给一个备份节点

2.Cluster关于Cluster的详情可参见http://tomcat.apache.org/tomcat-6.0-doc/cluster-howto.html ,Cluster是Manager的创建工厂,Cluster的接口非常简单,如下

public interface Cluster {
    public String getInfo();
    public String getClusterName();
    public void setClusterName(String clusterName);
    public void setContainer(Container container);
    public Container getContainer();
    public void setProtocol(String protocol);
    public String getProtocol();
    public Manager createManager(String name);
    public void registerManager(Manager manager);
    public void removeManager(Manager manager);
    public void backgroundProcess();
}

Cluster的实现只有一种org.apache.catalina.ha.tcp.SimpleTcpCluster,通过如下的配置范例,我们可以大概了解Cluster的主要结构,关于详细的实现,可以参见org.apache.catalina.ha包,代码相对比较独立,初始化和请求处理机制跟Tomcat机制类似,我们在前面中已有介绍。

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
                 channelSendOptions="8">

          <Manager className="org.apache.catalina.ha.session.DeltaManager"
                   expireSessionsOnShutdown="false"
                   notifyListenersOnReplication="true"/>

          <Channel className="org.apache.catalina.tribes.group.GroupChannel">
            <Membership className="org.apache.catalina.tribes.membership.McastService"
                        address="228.0.0.4"
                        port="45564"
                        frequency="500"
                        dropTime="3000"/>
            <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                      address="auto"
                      port="4000"
                      autoBind="100"
                      selectorTimeout="5000"
                      maxThreads="6"/>

            <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
              <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
            </Sender>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
          </Channel>

          <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
                 filter=""/>
          <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>

          <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
                    tempDir="/tmp/war-temp/"
                    deployDir="/tmp/war-deploy/"
                    watchDir="/tmp/war-listen/"
                    watchEnabled="false"/>

          <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
          <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
        </Cluster>
 

相关推荐