小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

TOMCAT的安全域(Realm)

 石榴 2007-08-29

安全域是Tomcat服務(wù)器用來保護(hù)Web應(yīng)用的資源的一種機(jī)制。在安全域中可以配置安全驗證信息,即用戶信息(包括用戶名和口令)以及用戶和角色的映射關(guān)系。每個用戶可以擁有一個或多個角色,每個角色擁有不同的可以訪問的Web資源。一個用戶可以訪問其擁有的所有角色對應(yīng)的Web資源。

引入角色的原因:角色一方面代表一系列用戶,另外一方面可以代表一系列權(quán)限,因此可以說是用戶和權(quán)限的結(jié)合體。引入角色的概念主要是為了分離用戶和訪問權(quán)限的直接聯(lián)系。用戶與訪問權(quán)限的直接組合可能是短暫的,而角色則可以相對穩(wěn)定,這樣用戶的變化只要涉及到角色就可以,無需考慮權(quán)限。而權(quán)限的變化只涉及到角色,無需考慮用戶或用戶組。

安全域是Tomcat的內(nèi)置功能,在org.apache.catalina.Realm接口中聲明了把一組用戶名、口令及所關(guān)聯(lián)的角色集成到Tomcat中的方法。Tomcat 5提供了4個實現(xiàn)這一接口的類,它們分別代表了五種安全域類型:

安全域類型

類名

描述

內(nèi)存域

MemoryRealm

在初始化階段,從XML文件中讀取安全認(rèn)證信息,并把它們以一組對象的形式存放在內(nèi)存中

JDBC

JDBCRealm

通過JDBC驅(qū)動程序訪問存放在數(shù)據(jù)庫中的安全驗證信息

數(shù)據(jù)源域

DataSourceRealm

通過JNDI數(shù)據(jù)源訪問存放在數(shù)據(jù)庫中的安全驗證信息

JNDI

JNDIRealm

通過JNDI provider訪問存放在基于LDAP的目錄服務(wù)器中的安全驗證信息。

JAAS

JAASRealm

通過JAAS的安全授權(quán)API,實現(xiàn)自己的安全認(rèn)證機(jī)制


要達(dá)到保護(hù)Web資源需要涉及到配置一些文件,但不管配置哪一種安全域,一般都包含以下步驟:
(1)為Web資源設(shè)置安全約束,通過為Web資源設(shè)置安全約束,可以指定某種Web資源可以被哪些角色訪問。這個設(shè)置需要在Web應(yīng)用的web.xml文件中加入、元素。

//聲明受保護(hù)的資源
The Entire Web Application

//標(biāo)識受保護(hù)的Web資源
*.jsp//指定受保護(hù)的URL路徑
*.do
*.html
*.htm

//可以訪問受保護(hù)資源的角色,可以包含多個角色
tomcat//指定可以訪問受保護(hù)資源的角色

//這個元素指定了當(dāng)Web客戶訪問受保護(hù)的Web資源時,系統(tǒng)彈出的登錄對話框的類型。
FORM//指定驗證方法。它有三個可選值:BASIC(基本驗證)、DIGEST(摘要驗證)、FORM(基于表單的驗證)。
Tomcat Supported Realm//設(shè)定安全域的名稱
//配置驗證網(wǎng)頁和出錯網(wǎng)頁
/login.jsp//設(shè)定驗證網(wǎng)頁
/login_fail.jsp//設(shè)定出錯網(wǎng)頁

//指明這個Web應(yīng)用引用的所有角色名字。
An example role defined in "conf/tomcat-users.xml"
tomcat//設(shè)定tomcat角色

以上安全約束代碼指定了tomcat角色才能訪問admin應(yīng)用中的*.jsp、*.do、*.htm、*.html資源。
 

基本驗證

如果采用基本驗證,當(dāng)客戶訪問受保護(hù)的資源時,瀏覽器會先彈出一個對話框,要求用戶輸入用戶名和密碼,如果輸入正確,Web服務(wù)器就允許他訪問這些資源;否則,在連接3次嘗試失敗后,會顯示一個錯誤信息頁面。這個方法的缺點是把用戶名和密碼從客戶端傳送到Web服務(wù)器時,在網(wǎng)絡(luò)上傳送的數(shù)據(jù)采用Base64編碼(全是可讀文本),因此這種驗證方法不是非常安全。可以采用一些安全措施來克服這個弱點。例如在傳輸層上應(yīng)用SSL(安全套接層(Secure Sockets Layer)為驗證過程提供了數(shù)據(jù)加密,服務(wù)器端認(rèn)證,信息真實性等方面的安全保證。在此驗證方式中,客戶端必須提供一個公鑰證書,你可以把這個公鑰證書看作是你的數(shù)字護(hù)照。公鑰證書也稱數(shù)字證書,它是被稱作證書授權(quán)機(jī)構(gòu)(CA)——一個被信任的組織頒發(fā)的。這個數(shù)字證書必須符合X509公鑰體系結(jié)構(gòu)(PKI)的標(biāo)準(zhǔn)。如果你指定了這種驗證方式,Web服務(wù)器將使用客戶端提供的數(shù)字證書來驗證用戶的身份。)或者在網(wǎng)絡(luò)層上使用IPSEC或VPN技術(shù)。

摘要驗證
摘要驗證與基本驗證的不同在于:摘要驗證不會在網(wǎng)絡(luò)中直接傳輸用戶密碼,而是首先采用MD5(Message Digest Algorithm)對用戶密碼進(jìn)行加密,然后傳輸加密后的數(shù)據(jù),所有這種方法顯得更為安全。
基于表單的驗證
基于表單的驗證使系統(tǒng)開發(fā)者可以自定義用戶的登陸頁面和報錯頁面。用戶在表單中填寫用戶名和密碼,而后密碼以明文形式在網(wǎng)路中傳遞,如果在網(wǎng)路的某一節(jié)點將此驗證請求截獲,在經(jīng)過反編碼很容易就可以獲取用戶的密碼。因此在使用基本HTTP的驗證方式和基于表單的驗證方法時,一定確定這兩種方式的弱點對你的應(yīng)用是可接受的。但有個規(guī)定:用戶名對應(yīng)的文本框必須命名為:j_username,密碼對應(yīng)的文本框必須命名為:j_password,并且表單的aciton的值必須為:j_security_check。

下面分別介紹4種安全域:

1、內(nèi)存域(MemoryReal)
內(nèi)存域是由org.apache.catalina.realm.MemoryRealm類來實現(xiàn)的。MermoryRealm從一個XML文件中讀取用戶信息。默認(rèn)情況下,該XML文件為tomcat安裝目錄的conf/tomcat_users.xml。













在這個文件中定義了每個用戶擁有的角色。
要采用這個類型的安全域進(jìn)行web資源保護(hù)的設(shè)置步驟為:
(1) 按上面的步驟在你的應(yīng)用程序的web.xml中配置安全約束,可以采用三種驗證(Basic、Digest、基于表單(Form))中的任一種。
(2) 在tomcat_user.xml文件中定義用戶、角色以及兩者的映射關(guān)系。
(3) 在server.xml中加入相應(yīng)的元素。

2、JDBC域
JDBCRealm通過JDBC驅(qū)動程序訪問存放在關(guān)系型數(shù)據(jù)庫中的安全認(rèn)證信息,JDBC域使得安全配置非常靈活。當(dāng)修改了數(shù)據(jù)庫中的安全認(rèn)證信息后,不必重啟tomcat服務(wù)器(兩者是相互獨立的)。
當(dāng)用戶第一次訪問受保護(hù)的資源時,Tomcat將調(diào)用Reaml的authenticate()方法,該方法從數(shù)據(jù)庫中讀取最新的安全認(rèn)證信息。該用戶通過認(rèn)證之后,在用戶訪問Web資源期間,用戶的各種驗證信息被保存在緩存中。
JDBC域設(shè)置步驟為:
(1)、按上面的步驟在你的應(yīng)用程序的web.xml中配置安全約束,可以采用三種驗證(Basic、Digest、基于表單(Form))中的任一種。
(2)、創(chuàng)建數(shù)據(jù)庫和創(chuàng)建兩張表:users(定義用戶信息,包括用戶名和口令)和users_roles(定義用戶和角色的映射關(guān)系)。
(3)、將所用的數(shù)據(jù)庫驅(qū)動程序拷貝到Tomcat安裝目錄下/common/lib中。
(4)、配置元素,在server.xml中的中加入如下的元素:如果中已經(jīng)有元素了,應(yīng)該將其注釋掉。
driverName=”com.mysql.jdbc.Driver” debug=”99”//數(shù)據(jù)庫驅(qū)程,debug設(shè)定跟蹤級別
connectionURL=”jdbc:mysql://localhost/database” //數(shù)據(jù)庫的URL
connectionName=”admin” connectionPassword=”8888” //數(shù)據(jù)庫連接的用戶名和口令
userTable=”users” userNameCol=”user_name” userCredCol=”user_pass”//指定用戶表
userRoleTable=”user_roles” roleNameCol=”role_name” />//指定用戶和角色映射關(guān)系表


 

3、DataSource域
DataSource域和JDBCRealm域的兩者的不同是訪問數(shù)據(jù)庫的方式不一樣:DataSource通過
JNDI來訪問數(shù)據(jù)庫。而JDBCRealm通過JDBC驅(qū)動程序來訪問數(shù)據(jù)庫。

區(qū)別:通過JDBC API連結(jié)數(shù)據(jù)庫是一種最原始、最直接的方法。而DataSource封裝了通過JDBC API來連結(jié)數(shù)據(jù)庫的細(xì)節(jié),它采用數(shù)據(jù)庫連結(jié)池機(jī)制,把可用的數(shù)據(jù)庫連結(jié)保存在緩存中,避免每次訪問數(shù)據(jù)庫都建立數(shù)據(jù)庫連結(jié),這樣可以提高訪問數(shù)據(jù)庫的效率。

適用場合: 在任何Java應(yīng)用中,都可以直接通過JDBC API連結(jié)數(shù)據(jù)庫,如果需要的話,可以手工編程實現(xiàn)數(shù)據(jù)庫連結(jié)池。當(dāng)Java應(yīng)用運行在JavaWeb容器或EJB容器中時,可以優(yōu)先考慮使用由容器提供的DataSource。以Tomcat容器為例,DataSource實例被作為JNDI資源發(fā)布到Tomcat容器中,Tomcat容器負(fù)責(zé)維護(hù)DataSource實例的生命周期,Java Web應(yīng)用通過JNDI來獲得DataSource實例的引用。

JNDI(The Java Naming and Directory Interface,Java命名和目錄接口)是一組在Java應(yīng)用中訪問命名和目錄服務(wù)的API。命名服務(wù)將名稱和對象聯(lián)系起來,使得我們可以用名稱訪問對象。目錄服務(wù)是一種命名服務(wù),在這種服務(wù)里,對象不但有名稱,還有屬性。

DataSource域配置步驟:
(1)、按上面的步驟在你的應(yīng)用程序的web.xml中配置安全約束,可以采用三種驗證(Basic、Digest、基于表單(Form))中的任一種。
(2)、創(chuàng)建數(shù)據(jù)庫和創(chuàng)建兩張表:users(定義用戶信息,包括用戶名和口令)和users_roles(定義用戶和角色的映射關(guān)系)。
(3)、將所用的數(shù)據(jù)庫驅(qū)動程序拷貝到Tomcat安裝目錄下/common/lib中。
(4)、數(shù)據(jù)源的配置
數(shù)據(jù)源的配置涉及修改server.xml和web.xml文件。
A、 在server.xml中元素下加入
元素。例如:

……
……
auth="Container" //指定管理Resource的Manager,又兩個可選值:Container和//Application。Container表示由容器來創(chuàng)建和管理//Resource,而Application表示由應(yīng)用程序//來創(chuàng)建和管理Resource。
type="javax.sql.DataSource"/> //指定Resource所屬的java類名
//指定配置TestDB數(shù)據(jù)源的參數(shù)

factory //指定生成DataSource的factory的類名
org.apache.commons.dbcp.BasicDataSourceFactory



maxActive
100



maxIdle
30



maxWait
10000



username
test


password
test



driverClassName
org.gjt.mm.mysql.Driver



url
jdbc:mysql://localhost:3306/test



注意:Tomcat的JNDI資源必須配置在元素下,服務(wù)器才能找到,否則會出現(xiàn)NameNotFoundException;低于Tomcat5.0.12的版本,即使正確配置了DataSourceRealm,也會出現(xiàn)找不到JNDI DataSource的異常,這個小貓的一個bug;在web.xml中是不需要配置元素的,因為Web應(yīng)用并不會訪問這個DataSource。(5)在server.xml添加和JDBC域幾乎相同的代碼:
driverName="com.mysql.jdbc.Driver" debug="99"
connectionURL="jdbc:mysql://localhost/tomcatusers"
connectionName="admin" connectonPassword=""
userTable="users" userNameCol="user_name" userCredCol="user_pass"
userRoleTable="user_roles" roleNameCol="role_name"/>

javax.naming.Context提供了查找JNDI Resource的接口,可通過如下的代碼獲得數(shù)據(jù)源的引用和連接數(shù)據(jù)庫:
Context ctx = new Context();
DatatSource ds = (DataSource)ctx.lookup(“java:comp/env/jdbc/TestDB”);
Connection conn = ds.getConnection();
java:comp/env代表你的JVM的環(huán)境
 
 

4、JNDIRealm
JNDI Directory Realm將Catalina連接到一個LDAP目錄,通過正確的JNDI驅(qū)動訪問。LDAP目錄存儲了用戶名,密碼以及他們相應(yīng)的角色。LDAP(輕量級目錄訪問協(xié)議)的英文全稱是Lightweight Directory Access Protocol,LDAP是用來訪問存儲在信息目錄(也就是LDAP目錄)中的信息的協(xié)議。更為確切和正式的說法應(yīng)該是 “通過使用LDAP,可以在信息目錄的正確位置讀取(或存儲)數(shù)據(jù)”。LDAP最大的優(yōu)勢是:可以在任何計算機(jī)平臺上,用很容易獲得的而且數(shù)目不斷增加的LDAP的客戶端程序訪問LDAP目錄。而且也很容易定制應(yīng)用程序為它加上LDAP的支持。

JNDI Realm支持許多使用LDAP進(jìn)行認(rèn)證的方法:
a、realm可以使用模式來決定用戶目錄條目的唯一名字(distinguished name),或者搜索目錄來定位該條目;
b、realm可以將用戶條目的唯一名字和用戶給出的密碼綁定到目錄上,對用戶進(jìn)行認(rèn)證;或者,從用戶條目中取出密碼,在本地進(jìn)行比較;
c、在目錄中,角色可以以單獨的條目存在(比如,用戶所屬的組條目),或者,角色可以是用戶條目的一個屬性,或者兩種情況都是;
除了到目錄的連接,用戶從目錄中獲取信息的元素和屬性名稱以外,Directory Realm還支持很多其他的附加屬性:
屬性 描述
authentication 使用的認(rèn)證類型,字符串類型??梢允恰皀one”,“simple”,“strong”或者提供者定義的其他類型,如果沒有值,使用提供者提供的缺省值。

connectionName 創(chuàng)建目錄連接使用的目錄用戶名。如果沒有指定,使用匿名連接,這在大多數(shù)情況下就足夠了,除非你指定了userPassword屬性

connectionPassword 創(chuàng)建目錄連接使用的目錄密碼。如果沒有指定,使用匿名連接,這在大多數(shù)情況下就足夠了,除非你指定userPassword屬性。

connectionURL 創(chuàng)建目錄連接時,傳遞給JNDI驅(qū)動的連接URL。

contextFactory 用來取得JNDI InitialContext的工廠類的Java類名。缺省情況下,假定使用標(biāo)準(zhǔn)的JNDI LDAP提供者。

protocol 使用的安全協(xié)議。如果沒有指定,使用提供者提供的缺省值。

roleBase 用于角色查找的基準(zhǔn)目錄條目。如果沒有指定,使用目錄上下文的頂級元素。

roleName 在角色查找中,包含角色名的屬性的名稱。另外,在用戶條目中,你可以使用userRoleName來指定包含額外角色名的屬性名稱,。如果沒有指定,不搜索角色,角色存在于用戶條目中。

roleSearch 用來進(jìn)行角色查找的LDAP過濾器表達(dá)式。使用{0}來代替用戶的唯一名稱,{1}來代替用戶名。如果沒有指定,不對角色進(jìn)行搜索,角色從用戶條目中由userRoleName指定的屬性得到。

roleSubtree 在查找與用戶相關(guān)聯(lián)的角色時,如果想搜索由roleBase屬性指定的元素的整個子樹,設(shè)為true。缺省值為false,只對頂級元素進(jìn)行搜索。

userBase 在使用userSearch表達(dá)式搜索用戶的時候的基準(zhǔn)元素。如果使用userPattern表達(dá)式進(jìn)行搜索,不使用這個屬性。

userPassword 在用戶條目中包含用戶密碼的屬性名。如果指定了這個值,JNDIRealm使用connectionName和connectionPassword屬性指定的值綁定到目錄,取出對應(yīng)的屬性,與被認(rèn)證的用戶給出的值進(jìn)行比較。如果不指定這個值,JNDIRealm會嘗試使用用戶條目的唯一名稱和用戶給出的密碼綁定到目錄,如果綁定成功,說明認(rèn)證成功。

userPattern 用戶目錄條目的唯一名稱的模式,{0}代表實際的用戶名。在唯一名稱包含用戶名,其他的項都相同的時候,可以使用這個屬性,而不是使用userSearch,userSubtree和userBase.

userRoleName 用戶目錄條目中的一個屬性名,該屬性包含了零個或多個指定給用戶的角色名的值。另外,如果角色以單獨的條目存在,可以使用roleName屬性來指定屬性名,在搜索目錄的時候,可以得到這個屬性。
如果不指定userRoleName,用戶的所有角色通過角色搜索得到;

userSearch 搜索用戶目錄條目時,使用的LDAP過濾表達(dá)式,{0}代表實際的用戶名,可以使用userSearch,userBase和userSubtree屬性一起來代替userPattern搜索目錄。

userSubtree 如果希望搜索由userBase屬性指定的元素的整個子樹,設(shè)為true,缺省值為false,即只搜索頂級元素。如果使用userPattern表達(dá)式,不使用這個屬性。

5、JAASRealm
Java Authentication Authorization Service(JAAS,Java驗證和授權(quán)API)提供了靈活和可伸縮的機(jī)制來保證客戶端或服務(wù)器端的Java程序。JAAS是一個比較新的的Java API。在J2SE 1.3中,它是一個擴(kuò)展包;在J2SE 1.4中變成了一個核心包。通過實現(xiàn)以下兩個接口:javax.security.auth.spi.LoginModule 和javax.security.Principal,你可以實現(xiàn)自己的安全機(jī)制。
 
 
 
配置的步驟:
a、實現(xiàn)自己的LoginMode、User和Role的類。
b、盡管不是JAAS要求,但你應(yīng)該通過javax.security.Principal這個接口實現(xiàn)一個單獨的類來區(qū)別users和roles,這樣tomcat就能區(qū)分哪個Principals是users和roles返回。
C、設(shè)置login.config文件告訴tomcat去哪里找指定的JVM。
D、配置web.xml文件,和前面的配置一樣。
E、在server.xml文件中加入<Realm>元素。
--------my.MyLoginModule.java---------------
package my;
import java.util.Map;
import java.security.Principal;
import javax.security.auth.login.LoginContext;
import javax.security.auth.Subject;
import javax.security.auth.callback.*;
import javax.security.auth.login.*;
import javax.security.auth.spi.LoginModule;
import java.io.IOException;
public class MyLoginModule implements LoginModule {
    protected CallbackHandler callbackHandler = null;
    protected boolean committed = false;
    protected boolean debug = false;
    protected Map options = null;
    protected Principal principal = null;
    protected Map sharedState = null;
    protected Subject subject = null;
    protected void log(String message) {
        System.out.print("MyLoginModule: ");
        System.out.println(message);
    }
    public boolean abort() throws LoginException {
        log("abort");  
        return (true);
    }
    public boolean commit() throws LoginException {
        log("commit phase");
        // If authentication was not successful, just return false
        if (principal == null){
            log("no principal commit fails");
            return (false);
        }
        if (!subject.getPrincipals().contains(principal))
            subject.getPrincipals().add(principal);
        // add role principals
        subject.getPrincipals().add(new MyRolePrincipal("admin"));
        committed = true;
        log("commit succesful");
        return (true);
    }
    public void initialize(Subject subject, CallbackHandler callbackHandler,
                           Map sharedState, Map options) {
        // Save configuration values
        this.subject = subject;
        this.callbackHandler = callbackHandler;
        this.sharedState = sharedState;
        this.options = options;
    }
   public boolean login() throws LoginException {
        log("login phase");
        // Set up our CallbackHandler requests
        if (callbackHandler == null)
            throw new LoginException("No CallbackHandler specified");
        Callback callbacks[] = new Callback[2];
        callbacks[0] = new NameCallback("Username: ");
        callbacks[1] = new PasswordCallback("Password: ", false);
        // Interact with the user to retrieve the username and password
        String username = null;
        String password = null;
        try {
            callbackHandler.handle(callbacks);
            username = ((NameCallback) callbacks[0]).getName();
            password =
           new String(((PasswordCallback) callbacks[1]).getPassword());
        } catch (IOException e) {
            throw new LoginException(e.toString());
        } catch (UnsupportedCallbackException e) {
            throw new LoginException(e.toString());
        }
        if (!authenticate(username,password))
            return false;
        principal  = new MyPrincipal(username);
        return true;
    }
    public boolean logout() throws LoginException {
        subject.getPrincipals().remove(principal);
        committed = false;
        principal = null;
        return (true);
 
    }
    boolean authenticate(String s,String p){
       return (s.compareTo("jaas") == 0) && (p.compareTo("jaas") == 0);  
    }
   
    static public void main(String args[]) throws Exception{
        LoginContext ctx = new LoginContext("TomCatAdminApplication");
        ctx.login();
       
    }
 
}
------------------------------------------------
---------my/MyPrincipal.java-------------------
package my;
public class MyPrincipal implements java.security.Principal {
    String m_Name = new String("");
    public MyPrincipal(String name) {
        m_Name = name;
    }
    public boolean equals(Object another) {
        try {
            MyPrincipal pm = (MyPrincipal)another;
            return pm.m_Name.equalsIgnoreCase(m_Name);
        } catch(Exception e){
            return false;  
        }
    }
    public String getName() {
        return m_Name;
    }
    public int hashCode() {
        return m_Name.hashCode();
    }
    public String toString() {
        return  m_Name;
    }
}
------my/MyRolePrincipal.java-------------
package my;
 
public class MyRolePrincipal extends MyPrincipal {
    /** Creates a new instance of MyRolePrincipal */
    public MyRolePrincipal(String s) {
        super(s);
    }
}
--------------------------------------
在 server.xml中配置
<Context ..Tomcat Administration..>
<Realm className="org.apache.catalina.realm.JAASRealm" debug="3" appName="TomCatAdminApplication" userClassNames="my.MyPrincipal" roleClassNames="my.MyRolePrincipal">
</Realm>
</Context>

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多