<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    上善若水
    In general the OO style is to use a lot of little objects with a lot of little methods that give us a lot of plug points for overriding and variation. To do is to be -Nietzsche, To bei is to do -Kant, Do be do be do -Sinatra
    posts - 146,comments - 147,trackbacks - 0

    概述

    Jetty的強(qiáng)大之處在于可以自由的配置某些組建的存在與否,以提升性能,減少?gòu)?fù)雜度,而其本身也因?yàn)檫@種特性而具有很強(qiáng)的可擴(kuò)展性。SecurityHandler就是Jetty對(duì)Servlet中Security框架部分的實(shí)現(xiàn),并可以根據(jù)實(shí)際需要裝卸和替換。Servlet的安全框架主要有兩個(gè)部分:數(shù)據(jù)傳輸?shù)陌踩约皵?shù)據(jù)授權(quán),對(duì)數(shù)據(jù)傳輸?shù)陌踩梢允褂肧SL對(duì)應(yīng)的Connector實(shí)現(xiàn),而對(duì)于數(shù)據(jù)授權(quán)安全,Servlet定義了一套自己的框架。

    Servlet的安全框架支持兩種方式的驗(yàn)證:首先,是用于登陸的驗(yàn)證,對(duì)于定義了role-name的資源都需要進(jìn)行登陸驗(yàn)證,Servlet支持NONE、BASIC、CLIENT-CERT、DIGEST、FORM等5種驗(yàn)證方式(<login-config>/<auth-method>);除了用戶登陸驗(yàn)證,Servlet框架還定義了role的概念,一個(gè)role可以包含一個(gè)或多個(gè)用戶,一個(gè)用戶可以隸屬于多個(gè)role,一個(gè)資源可以有一個(gè)或多個(gè)role,只有這些定義的role才能訪問(wèn)該資源,用戶只能訪問(wèn)它所隸屬的role能訪問(wèn)的資源。另外,對(duì)一個(gè)Servlet來(lái)說(shuō),還可以定義role-name到role-link的映射關(guān)系,從文檔上,這里的role-name是Servlet中使用的名字,而role-link是Container中使用的名字,感覺(jué)很模糊,從Jetty的角度,role-name是web.xml中在<security-constraint>/<auth-constraint>/<role-name>中對(duì)一個(gè)URL Pattern的role定義,而role-link則是UserIdentity中roles數(shù)組的值,而UserIdentity是LoginService中創(chuàng)建的,它從文件、數(shù)據(jù)庫(kù)等加載已定義的user的信息:用戶名、密碼、它隸屬的role等,如果Servlet中沒(méi)有定義role-name到role-link的映射,則直接使用role-name去UserIdentity中比較role信息。

    關(guān)于Servlet對(duì)Security框架的具體解釋,可以參考Oracle的文檔:http://docs.oracle.com/cd/E19798-01/821-1841/6nmq2cpk7/index.html

    在web.xml中,對(duì)用于登陸驗(yàn)證方式的定義如下:
       <login-config> 
         <auth-method>FORM</auth-method> 
         <realm-name>Example-Based Authentiation Area</realm-name> 
         <form-login-config> 
            <form-login-page>/jsp/security/protected/login.jsp</form-login-page> 
            <form-error-page>/jsp/security/protected/error.jsp</form-error-page> 
         </form-login-config> 
       </login-config> 
    OR
      <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>Tomcat Manager Application</realm-name>
      </login-config>
    而對(duì)資源所屬role的定義如下:
      <security-constraint>
      <security-constraint>
        <web-resource-collection>
          <web-resource-name>Status interface</web-resource-name>
          <url-pattern>/status/*</url-pattern>
        </web-resource-collection>
        ...
        <auth-constraint>
           <role-name>manager-gui</role-name>
           <role-name>manager-script</role-name>
           <role-name>manager-jmx</role-name>
           <role-name>manager-status</role-name>
        </auth-constraint>
      </security-constraint>

    Jetty對(duì)Servlet Security實(shí)現(xiàn)概述和類(lèi)圖

    在Jetty中,使用Authenticator接口抽象不同用戶登陸驗(yàn)證的邏輯;使用LoginService接口抽象對(duì)用戶名、密碼的驗(yàn)證;使用UserIdentity保存內(nèi)部定義的一個(gè)用戶的用戶名、密碼、role集合;使用ConstraintMapping保存URL Pattern到role集合的映射;使用UserIdentity.Scope保存一個(gè)Servlet中role-name到role-link的映射。他們的類(lèi)圖如下:

    UserIdentity實(shí)現(xiàn)

    UserIdentity表示一個(gè)用戶的認(rèn)證信息,它包含Subject和UserPrincipal,其中Subject是Java Security框架定義的類(lèi)型,而UserPrincipal則用于存儲(chǔ)用戶名以及認(rèn)證信息,在Jetty中一般使用KnownUser來(lái)存儲(chǔ),它包含了UserName以及Credential實(shí)例,其中Credential可以是Crypt、MD5、Password等。在Credential中定義了check方法用于驗(yàn)證傳入的credential是否是正確的。

    IdentityService實(shí)現(xiàn)

    IdentityService我猜原本用于將UserIdentity、RunAsToken和當(dāng)前Thread關(guān)聯(lián)在一起,以及創(chuàng)建UserIdentity、RunAsToken,然而我看的版本中,DefaultIdentityService貌似還沒(méi)有實(shí)現(xiàn)完成,目前只是根據(jù)提供的Subject、Principal、roles創(chuàng)建DefaultUserIdentity實(shí)例,以及使用runAsName創(chuàng)建RoleRunAsToken,對(duì)Servlet中的runAsToken,我看的Jetty版本也還沒(méi)有實(shí)現(xiàn)完成。
        public UserIdentity newUserIdentity(final Subject subject, final Principal userPrincipal, final String[] roles) {
            return new DefaultUserIdentity(subject,userPrincipal,roles);
        }
        public RunAsToken newRunAsToken(String runAsName) {
            return new RoleRunAsToken(runAsName);
        }

    LoginService實(shí)現(xiàn)

    在Jetty中,LoginService用來(lái)驗(yàn)證給定的用戶名和證書(shū)信息(如密碼),即對(duì)應(yīng)的login方法;以及驗(yàn)證給定的UserIdentity,即對(duì)應(yīng)的validate方法;其N(xiāo)ame屬性用于標(biāo)識(shí)實(shí)例本身(即作為當(dāng)前使用的realm name);另外IdentityService用于根據(jù)加載的用戶名和證書(shū)信息創(chuàng)建UserIdentity實(shí)例。
    public interface LoginService {
        String getName();
        UserIdentity login(String username,Object credentials);
        boolean validate(UserIdentity user);
        IdentityService getIdentityService();
        void setIdentityService(IdentityService service);
        void logout(UserIdentity user);
    }

    為了驗(yàn)證用戶提供的用戶名和證書(shū)的正確性和合法性,需要有一個(gè)地方用來(lái)存儲(chǔ)定義好的正確的用戶名以及對(duì)應(yīng)的證書(shū)信息(如密碼等),Jetty提供了DB、Properties文件、JAAS、SPNEGO作為用戶信息源的比較。對(duì)于DB或Properties文件方式存儲(chǔ)用戶信息,如果每次的驗(yàn)證都去查詢數(shù)據(jù)庫(kù)或讀取文件內(nèi)容,效率會(huì)很低,因而還有一種實(shí)現(xiàn)方式是將數(shù)據(jù)庫(kù)或文件中定義的用戶信息預(yù)先的加載到內(nèi)存中,這樣每次驗(yàn)證只需要讀取內(nèi)存即可,這種方式的實(shí)現(xiàn)性能會(huì)提高很多,但是這樣就無(wú)法動(dòng)態(tài)的修改用戶信息,并且如果用戶信息很多,會(huì)占用很多的內(nèi)存,目前Jetty采用后者實(shí)現(xiàn),其中數(shù)據(jù)庫(kù)存儲(chǔ)用戶信息有兩個(gè):JDBCLoginService以及DataSourceLoginService,Properties文件存儲(chǔ)對(duì)應(yīng)的實(shí)現(xiàn)是HashLoginService,它們都繼承自MappedLoginService。在MappedLoginService中保存了一個(gè)ConcurrentMap<String, UserIdentity>實(shí)例,它是一個(gè)UserName到UserIdentity的映射,在該實(shí)例start時(shí),它會(huì)從底層的數(shù)據(jù)源中加載用戶信息,對(duì)HashLoginService,它會(huì)從config指定的Properties文件中加載用戶信息,并填充ConcurrentMap<String, UserIdentity>,其中Properties文件的格式為:<username>=credential, role1, role2, ....如果credential以"MD5:"開(kāi)頭,表示它是MD5數(shù)據(jù),如果以"CRYPT:"開(kāi)頭,表示它是crypt數(shù)據(jù),否則表示它是密碼字符;如果以存在的用戶不在新讀取的用戶列表中,則將其移除,因?yàn)镠ashLoginService還可以啟動(dòng)一個(gè)線程以隔一定的時(shí)間重新加載文件中的內(nèi)容,以處理文件更新的問(wèn)題。在MappedLoginService中還定義了幾個(gè)Principal的實(shí)現(xiàn)類(lèi):KnownUser、RolePrincipal、Anonymous等,在添加加載的用戶時(shí),使用KnownUser保存username和credential信息,并將該P(yáng)rincipal添加到Subject的Principals集合中,同時(shí)對(duì)每個(gè)role創(chuàng)建RolePrincipal,并添加到Subject的Principals集合中,而將credential添加到Subject的PrivateCredentials集合中,使用IdentityService創(chuàng)建UserIdentity,并添加到ConcurrentMap<String, UserIdentity>中。在login驗(yàn)證中,首先使用傳入的username查找存在的UserIdentity,并使用找到的UserIdentity中的Principal的check方法驗(yàn)證傳入的credential,如果驗(yàn)證失敗,返回null(即調(diào)用Credential的check方法:Password/MD5/Crypt)。對(duì)DataSourceLoginService和JDBCLoginService只是從數(shù)據(jù)庫(kù)中加載用戶信息,不詳述。而JAASLoginService和SpnegoLoginService也只是使用各自的協(xié)議進(jìn)行驗(yàn)證,不細(xì)述。

    Authenticator實(shí)現(xiàn)

    Authenticator用于驗(yàn)證傳入的ServletRequest、ServletResponse是否包含正確的認(rèn)證信息。其接口定義如下:
    public interface Authenticator {
        // Jetty支持BASIC、FORM、DIGEST、CLIENT_CERT、SPNEGO的認(rèn)證,該方法返回其中的一種,或用于自定義的方法。
        String getAuthMethod();

        // 設(shè)置配置信息(SecurityHandler繼承自AuthConfiguration接口):AuthMethod、RealmName、InitParameters、LoginService、IdentityService、IsSessionRenewedOnAuthentication
        void setConfiguration(AuthConfiguration configuration);
        
        // 驗(yàn)證邏輯的實(shí)現(xiàn)方法,其中mandatory若為false表示當(dāng)前資源有沒(méi)有配置role信息,或者@ServletSecurity中的@HttpConstraint的EmptyRoleSemantic被配置為PERMIT,此時(shí)返回Deferred類(lèi)型的Authentication,如果不手動(dòng)的調(diào)用其authenticate或login方法,就不會(huì)對(duì)該請(qǐng)求進(jìn)行驗(yàn)證。
        // 對(duì)BasicAuthenticator的實(shí)現(xiàn),它從Authorization請(qǐng)求頭中獲取認(rèn)證信息(用戶名和用戶密碼,使用":"分割,并且使用Base64編碼),調(diào)用LoginService進(jìn)行認(rèn)證,當(dāng)認(rèn)證通過(guò)時(shí),如果配置了renewSession為true,則將HttpSession中的所有屬性更新一遍,并且添加(org.eclipse.jetty.security.secured, True) entry,并使用UserIdentity以及AuthMethod創(chuàng)建UserAuthentication返回。如果認(rèn)證失敗,則返回401 Unauthorized錯(cuò)誤,并且在相應(yīng)消息中包含頭:WWW-Authenticate: basic realm=<LoginService.name>
        // 對(duì)FormAuthenticator的實(shí)現(xiàn),它首先要配置formLoginPage、formLoginPath(默認(rèn)j_security_check)、formErrorPage、formErrorPath;只有當(dāng)前請(qǐng)求URL是formLoginPath時(shí),從j_username和j_password請(qǐng)求參數(shù)中獲取username和password信息,使用LoginService驗(yàn)證,如果驗(yàn)證通過(guò)且這個(gè)請(qǐng)求是因?yàn)橹罢?qǐng)求其他資源重定向過(guò)來(lái)的,這重定向到之前的URL,創(chuàng)建一個(gè)SessionAuthentication放入HttpSession中,并返回一個(gè)新創(chuàng)建的FormAuthentication;如果驗(yàn)證失敗,如果沒(méi)定義formErrorPage,返回403 Forbidden相應(yīng),否則重定向或forward到formErrorPage;對(duì)于其他URL請(qǐng)求,查看在當(dāng)前Session中是否存在已認(rèn)證的Authentication,如果有,但是重新驗(yàn)證緩存的Authentication失敗,則將這個(gè)Authentication從HttpSession中移除;否則返回這個(gè)Session中的Authentication;對(duì)于其他情況,表示當(dāng)前請(qǐng)求需要認(rèn)證后才能訪問(wèn),此時(shí)保存當(dāng)前請(qǐng)求URI以及POST數(shù)據(jù)到Session中,以在認(rèn)證之后可以直接跳轉(zhuǎn),然后重定向或forward到formLoginPage中。
        // 對(duì)DigestAuthenticator的實(shí)現(xiàn)類(lèi)似BasicAuthenticator,只是它使用Digest的方式對(duì)認(rèn)證數(shù)據(jù)進(jìn)行加密和解密。
        // 對(duì)ClientCertAuthenticator則采用客戶端證書(shū)的方式認(rèn)證,SpnegoAuthenticator使用SPNEGO方式認(rèn)證,JaspiAuthenticator使用JASPI方式認(rèn)證。 

        Authentication validateRequest(ServletRequest request, ServletResponse response, boolean mandatory) throws ServerAuthException;
        
        // 只用于JaspiAuthenticator,用于所有后繼handler處理完成后對(duì)ServletRequest、ServletResponse、User的進(jìn)一步處理,目前不了解JASPI的協(xié)議邏輯,因而不了解具體的用途。
        boolean secureResponse(ServletRequest request, ServletResponse response, boolean mandatory, User validatedUser) throws ServerAuthException;
    }

    SecurityHandler與ConstraintSecurityHandler實(shí)現(xiàn)

    SecurityHandler繼承自HandlerWrapper,并實(shí)現(xiàn)了Authenticator.AuthConfiguration接口,因而它包含了realm、authMethod、initParameters、loginService、identityService、renewSession等字段,在其start時(shí),它會(huì)首先從ServletContext的InitParameters中導(dǎo)入org.eclipse.jetty.security.*屬性的值到其InitParameters中,如果LoginService為null,則從Server中查找一個(gè)已經(jīng)注冊(cè)的LoginService,使用Authenticator.Factory根據(jù)AuthMethod創(chuàng)建對(duì)應(yīng)的Authenticator實(shí)例。

    ConstraintSecurityHandler繼承自SecurityHandler類(lèi),它定義了ConstraintMapping列表、所有定義的role、以及pathSpec到Map<String, RoleInfo>(key為httpMethod,RoleInfo包含UserDataConstraint枚舉類(lèi)型和roles集合)的映射,其中ConstraintMapping中保存了method、methodOmissions、pathSpec、Constraint(Constraint中包含了name、roles、dataConstraint等信息),ConstraintMapping在解析web.xml文件時(shí)添加,它對(duì)應(yīng)<security-constraint>下的配置,如auth-constraint下的role-name配置對(duì)應(yīng)roles數(shù)組,user-data-contraint對(duì)應(yīng)dataConstraint,web-resource-name對(duì)應(yīng)name,http-method對(duì)應(yīng)method,url-pattern對(duì)應(yīng)pathSpec;在每次添加ConstraintMapping時(shí)都會(huì)更新roles列表以及pathSpec到Map<String, RoleInfo>的映射。

    在SecurityHandler的handle方法中,它只需要對(duì)REQUEST、ASYNC類(lèi)型的DispatcherType需要驗(yàn)證:它首先根據(jù)pathInContext和Request實(shí)例查找RoleInfo信息;如果RoleInfo處于forbidden狀態(tài),發(fā)送403 Forbidden相應(yīng),如果DataConstraint配置了Intergal、Confidential,但是Connector中沒(méi)有配置相應(yīng)的port,則發(fā)送403 Forbidden相應(yīng),否則重定向請(qǐng)求到Integral、Confidential對(duì)應(yīng)的URL;對(duì)沒(méi)有驗(yàn)證過(guò)的請(qǐng)求調(diào)用Authenticator.validateRequest()對(duì)請(qǐng)求進(jìn)行驗(yàn)證;如果驗(yàn)證的結(jié)果是Authentication.ResponseSent,設(shè)置Request的handled為true,如果為Authentication.User,表示認(rèn)證成功,設(shè)置該Authentication到Request中,并檢查role,即檢查當(dāng)前User是否處于RoleInfo中的role集合中,如果不是,發(fā)送403 Forbidden響應(yīng),否則調(diào)用下一個(gè)handler的handle方法,之后調(diào)用Authenticator.secureResponse()方法;如果驗(yàn)證結(jié)果是Authentication.Deferred,在調(diào)用下一個(gè)handler的handle方法后調(diào)用Authenticator.secureResponse()方法;否則直接調(diào)用Authenticator.secureResponse()方法。
    posted on 2014-05-18 22:02 DLevin 閱讀(3344) 評(píng)論(2)  編輯  收藏 所屬分類(lèi): Jetty

    FeedBack:
    # re: 深入Jetty源碼之SecurityHandler
    2014-05-22 17:41 | 柚子舍cc霜
    介紹的很深入,看的蒙了。。  回復(fù)  更多評(píng)論
      
    # re: 深入Jetty源碼之SecurityHandler
    2016-04-18 18:23 | 小zhao
    我想問(wèn)一下,你這個(gè)有沒(méi)有樣例可以參考一下,我剛?cè)雑etty不久,對(duì)于這個(gè)LoginService的配置不是很熟悉,可以介紹一下,郵箱1204219804@qq.com  回復(fù)  更多評(píng)論
      
    主站蜘蛛池模板: 男女交性永久免费视频播放| h视频在线观看免费完整版| 国产一级淫片免费播放电影| 亚洲中文字幕无码av永久| 四虎国产精品免费久久| 亚洲人成电影网站| 日本精品人妻无码免费大全| 亚洲jizzjizz在线播放久| 免费无码肉片在线观看| 亚洲熟妇无码一区二区三区导航| 卡1卡2卡3卡4卡5免费视频| 亚洲av永久无码精品秋霞电影秋 | 99在线免费观看视频| 久久亚洲AV午夜福利精品一区| 精品免费tv久久久久久久| 亚洲最大的成网4438| 国产一卡二卡四卡免费| 亚洲天然素人无码专区| 国产一区在线观看免费| 国产无遮挡又黄又爽免费网站 | 亚洲黑人嫩小videos| 在线观看av永久免费| 男男黄GAY片免费网站WWW| 亚洲免费观看视频| 最近免费中文字幕大全免费 | 亚洲另类小说图片| 国产一区二区三区在线免费 | 国产性生大片免费观看性| 亚洲第一精品在线视频| 成熟女人牲交片免费观看视频| 极品色天使在线婷婷天堂亚洲| 亚洲日本va中文字幕久久| 精品国产污污免费网站aⅴ | 国产成人亚洲精品电影| 亚洲精品~无码抽插| 西西大胆无码视频免费| 九九九精品视频免费| 亚洲剧情在线观看| 亚洲欧洲日产国码一级毛片| 最近在线2018视频免费观看| 国产午夜亚洲精品不卡|