JAAS(二)

Java认证和授权服务(JAAS)供应器
15.1. 概述
Spring Security提供一个包,可以代理Java认证和授权服务(JAAS)的认证请求。 这个包的细节在下面讨论。
JAAS的核心是登录配置文件。 想要了解更多JAAS登录配置文件的信息,可以查询Sun公司的JAAS参考文档。 我们希望你对JAAS有一个基本了解,也了解它的登录配置语法,这才能更好的理解这章的内容。
15.2. 配置
这个 JaasAuthenticationProvider 通过JAAS认证用户的主体和证书。
让我们假设我们有一个JAAS登录配置文件,/WEB-INF/login.conf, 里边的内容如下:
JAASTest {
    sample.SampleLoginModule required;
};
就像所有的Spring Security bean一样,这个JaasAuthenticationProvider 要配置在application context里。 下面的定义是与上面的JAAS登录配置文件对应的:
<bean id="jaasAuthenticationProvider"
            class="org.springframework.security.providers.jaas.JaasAuthenticationProvider">
  <property name="loginConfig" value="/WEB-INF/login.conf"/>
  <property name="loginContextName" value="JAASTest"/>
  <property name="callbackHandlers">
    <list>
      <bean class="org.springframework.security.providers.jaas.JaasNameCallbackHandler"/>
      <bean class="org.springframework.security.providers.jaas.JaasPasswordCallbackHandler"/>
    </list>
  </property>
  <property name="authorityGranters">
    <list>
      <bean class="org.springframework.security.providers.jaas.TestAuthorityGranter"/>
    </list>
  </property>
</bean>
这个 CallbackHandler和AuthorityGranter会在下面进行讨论。
15.2.1. JAAS CallbackHandler
大多数JAAS的登录模块需要设置一系列的回调方法。 这些回调方法通常用来获得用户的用户名和密码。
在Spring Security发布的时候,Spring Security负责用户交互(通过认证机制)。 因此,现在认证请求使用JAAS代理,Spring Security的认证机制将组装一个Authentication对象,它包含了所有JAASLoginModule需要的信息。
因此,Spring Security的JAAS包提供两个默认的回调处理器,JaasNameCallbackHandler 和 JaasPasswordCallbackHandler。 他们两个都实现了JaasAuthenticationCallbackHandler。 大多数情况下,这些回调函数可以直接使用,不用了解它们的内部机制。
为了需要完全控制回调行为,内部JaasAutheticationProvider使 用一个InternalCallbackHandler封装这个JaasAuthenticationCallbackHandler。 这个InternalCallbackHandler才是 实际实现了JAAS通常的CallbackHandler接口。 任何时候JAASLoginModule被使用的时候,它 传递一个application context里配置的InternalCallbackHandler列 表。 如果这个LoginModule需要回调InternalCallbackHandler,回调会传递封装好的JaasAuthenticationCallbackHandler。
15.2.2. JAAS AuthorityGranter
JAAS工作在主体上。 任何“角色”在JAAS里都是作为主体表现的。 另一方面Spring Security使用Authentication对 象。 每个Authentication对象包含单 独的主体和多个GrantedAuthority[]。 为了方便映射不同的概念,Spring Security的JAAS包包含了AuthorityGranter接口。
一个 AuthorityGranter负责检查JAAS主 体,返回一个String的集合,用来表示分配给这个主体的权限。 对于每一个返回的权限字符串,JaasAuthenticationProvider会 创建一个JaasGrantedAuthority(它实现了Spring Security的GrantedAuthority接口),包含了AuthorityGranter返回的字符串和AuthorityGranter传递的JAAS主体。 JaasAuthenticationProvider获 得JAAS主体,通过首先成功认证用户的证书,使用JAAS的LoginModule,然后 调用LoginContext.getSubject().getPrincipals(), 使用返回的每个主体,传递到每个AuthorityGranter里,最后定义 在JaasAuthenticationProvider.setAuthorityGranters(List)属 性里。
Spring Security没有包含任何产品型的AuthorityGranter, 因为每个JAAS主体都有特殊实现的意义。 但是,这里的单元测试里有一个TestAuthorityGranter, 演示了一个简单的AuthorityGranter实现。



JAAS简介及实例
关键字: jaas 实例
JAAS是对JCE安全框架的重要补充,通过提供认证用户和确定用户授权来增强JAVA解决方案的动态安全性,使得资源能够得到很好得到保 护和控制(JAAS使用动态的安全策略来定义权限,而不是将其静态的嵌入到代码中)。

JAAS采用的是插件的运行方式,一开始就被设计 成可插拔的(Pluggable),根据应用的需要,只要配置一下JAAS的配置文件,这些组件即可包含 在我们的应用程序中。使用JAAS包接口,开发者和第三方可以开发一些组件或者BEAN来实现登陆认证,或者通过与使用者或外部的系统的进行交互来访问认 证信息(当然我们可以设计更为稳妥安全的密码学协议)。JAAS提供了一组用于用户鉴别的类和接口,这意味着支持JAAS的应用会要求用户登陆,同时 JAAS提供了另一组用于用户授权的类和接口。在讨论例子之前,先对JAAS API中常用的一些类和接口做个简单的说明。

LoginModule :确认用户的合法性(使用CallbackHandler或者其他类方法),并分配访问权限principal给subject;

LoginContext: 为了实现用户鉴别,建立相应的环境,从配置文件中导入规则;

CallbackHandler:回调处理器,负责与用户(代码拥有者和执 行者)交互,确认其身份的合法性;

Subject:表示登陆处理的目标,即一个被鉴别的用户。并可关联一个或多个pirncipal;

Principal:表示具有访问权限的一个实体,可以看作是可以执行某种操作的证件。

理解这些类和接口的关系我给 个生动的比方:一个军事学校,入学的时候校方(LoginModule)根据学生(Subject)的入学通知来确定其合法 性,这个过程交由某工作人员(CallbackHandler)执行,(CallbackHandler)确认后,(LoginModule)给不同 (Subject)根据其身份发给相关的证件(Principal),有了该证件就可以访问对应的资源,(Subject)根据自己的 (Principal)的级别可以使用和访问学校不同资源。

一个(Subject)的(Principal)如果是士官级,那么可以访 问的资源就相对少些,如果是将军级那就多些。当然一个(Subject)可以拥有多个(Principal)。

通过分析我们会发 现,JAAS采用的也是身份检查+权限分配模式。因此JAAS的应用也分成两个部分:(1)认证;(2)授权。过程是先认证后根据身份来授权(有歧视的嫌 疑的东东,本人可是反歧视人士)。

那么JAAS是如何实现认证的呢?又是如何实现授权的呢?且听我慢慢分解,将其妙处展现给大家。

二 JAAS的认证原理

(1) 设置JAAS配置文件,关于配置非常有技巧,跟设置防火墙的过滤规则有得一拼;

(2) 根据JAAS配置文件的条目加载一个或者多个LoginModule(通常一个,也可以变态得使用多个);

(3) 为了管理用户认证的有关过程,将提供一个可选的LoginModule构造函数和一个回调处理器CallbackHandler。如果没有在构造函数中提 供回调处理器,系统采用默认设置;

(4) 初始并实例化LoginContext(加载配置规则),如果成功,则调用LoginContext的login方法。无论是否需 要,LoginContext都会去首先读取JAAS配置文件,从中获得要加载的登陆模块信息,其initialize方法将按照配置文件中的相关内容提 供LoginModule运行所需要的信息;

(5) LoginContext的login方法将调用LoginModule的login方法,确定用户身份。该方法将设置相关的回调,并由回调处理器 CallbackHandler来管理登陆处理回调;

(6) LoginModule的login方法将负责与用户进行交互(可能是人机交互,也可能是机机交互),如果用户输入信息无效,则该方 法返回FALSE,一次交互过程结束,如果用户输入信息有效,则该方法将设置Principal对象的Subject对象,并返回TRUE;当然 LoginModule也可以将与用户之间的所有交互过程全部委托给处理器CallbackHandler来处理。如果登陆成功, LoginContext将调用LoginModule的commit方法将结果提交给LoginModule实例的内部状态。


  在应用程序中使用JAAS验证通常会涉及到以下几个步骤:

  1. 创建一个LoginContext的实例。

   2. 为了能够获得和处理验证信息,将一个CallBackHandler对象作为参数传送给LoginContext。

  3. 通过调用LoginContext的login()方法来进行验证。

  4. 通过使用login()方法返回的Subject对象实现一些特殊的功能(假设登录成功)。

  下面是一个简单的例子:

      SimpleLogin.java
      
Java代码
1. package com; 
2.  
3. import javax.security.auth.login.LoginContext; 
4. import javax.security.auth.login.LoginException; 
5.  
6. public class SimpleLogin { 
7.      
8.     public static void main(String[] args) { 
9.          
10.         // 建立登陆上下文,并通过配置文件初始化,在这里配置文件必须与程序同目录 
11.         LoginContext loginContext = null; 
12.         try { 
13.                                             
14.             loginContext = new LoginContext("simple", new SimpleCallbackHandle()); 
15.         } catch (LoginException e) { 
16.              
17.             System.out.println(e.getMessage()); 
18.         } 
19.          
20.         try { 
21.              
22.             // 如果不抛出异常表示验证成功 
23.             loginContext.login(); 
24.         } catch (LoginException e) { 
25.              
26.         } 
27.     } 
28.      
29. } 


   
   SimpleCallbackHandle.java
   
Java代码
1. package com; 
2.  
3. import java.io.BufferedReader; 
4. import java.io.IOException; 
5. import java.io.InputStreamReader; 
6. import javax.security.auth.callback.Callback; 
7. import javax.security.auth.callback.CallbackHandler; 
8. import javax.security.auth.callback.NameCallback; 
9. import javax.security.auth.callback.PasswordCallback; 
10. import javax.security.auth.callback.UnsupportedCallbackException; 
11.  
12. public class SimpleCallbackHandle implements CallbackHandler { 
13.  
14.     public void handle(Callback[] callbacks) throws IOException, 
15.             UnsupportedCallbackException { 
16.  
17.         for (Callback callback : callbacks) { 
18.  
19.             if (callback instanceof NameCallback) { 
20.                 NameCallback nc = (NameCallback) callback; 
21.                  
22.                 System.out.print(nc.getPrompt()); 
23.                 System.out.flush(); 
24.                  
25.                 nc.setName((new BufferedReader(new InputStreamReader( 
26.                                 System.in))).readLine()); 
27.             } else if (callback instanceof PasswordCallback) { 
28.                 PasswordCallback pcb = (PasswordCallback) callback; 
29.                  
30.                 System.out.print(pcb.getPrompt()); 
31.                 System.out.flush(); 
32.                 pcb.setPassword((new BufferedReader(new InputStreamReader( 
33.                         System.in))).readLine().toCharArray()); 
34.             } 
35.         } 
36.     } 
37. } 



SimpleLoginModule.java


Java代码
1. package com; 
2.  
3. import java.io.IOException; 
4. import java.util.Map; 
5.  
6. import javax.security.auth.Subject; 
7. import javax.security.auth.callback.Callback; 
8. import javax.security.auth.callback.CallbackHandler; 
9. import javax.security.auth.callback.NameCallback; 
10. import javax.security.auth.callback.PasswordCallback; 
11. import javax.security.auth.callback.UnsupportedCallbackException; 
12. import javax.security.auth.login.LoginException; 
13. import javax.security.auth.spi.LoginModule; 
14.  
15. public class SimpleLoginModule implements LoginModule{ 
16.  
17.     private String userName; 
18.      
19.     private char[] password; 
20.      
21.     private Subject subject; 
22.      
23.     private CallbackHandler callbackHandler; 
24.      
25.     private Map sharedState; 
26.      
27.     private Map options; 
28.      
29.     private String debug; 
30.      
31.     public boolean abort() throws LoginException { 
32.         System.out.println("abort()"); 
33.         return false; 
34.     } 
35.  
36.     public boolean commit() throws LoginException { 
37.         System.out.println("commit()"); 
38.         return false; 
39.     } 
40.  
41.     public void initialize(Subject subject, CallbackHandler callbackHandler, 
42.             Map sharedState, Map options) { 
43.          
44.         this.subject = subject; 
45.         this.callbackHandler = callbackHandler; 
46.         this.sharedState = sharedState; 
47.         this.options = options; 
48.          
49.         debug = (String)options.get("debug"); 
50.     } 
51.  
52.     public boolean login() throws LoginException { 
53.          
54.         Callback[] callbacks = new Callback[2]; 
55.         callbacks[0] = new NameCallback("用户名: "); 
56.         callbacks[1] = new PasswordCallback("密码: ", false); 
57.          
58.         try { 
59.              
60.             callbackHandler.handle(callbacks); 
61.             userName = ((NameCallback)callbacks[0]).getName(); 
62.             password = ((PasswordCallback)callbacks[1]).getPassword(); 
63.              
64.             if(debug.equals("true")){ 
65.                 System.out.println("你输入的用户名为:" + userName); 
66.                 System.out.println("你输入的密码为:" + new String(password)); 
67.             } 
68.              
69.             if(userName.equals("callan") && new String(password).equals("callanpass")){ 
70.                 System.out.println("验证成功"); 
71.                 return true; 
72.             } else { 
73.                 System.out.println("验证失败"); 
74.                 userName = null; 
75.                 password = null; 
76.             } 
77.         } catch (IOException e) { 
78.             e.printStackTrace(); 
79.         } catch (UnsupportedCallbackException e) { 
80.             e.printStackTrace(); 
81.         } 
82.          
83.         return false; 
84.     } 
85.  
86.     public boolean logout() throws LoginException { 
87.         System.out.println("logout()"); 
88.         return false; 
89.     } 
90.  
91. } 


jaas.config

Java代码
1. simple { 
2.    com.SimpleLoginModule required debug=true; 
3. }; 

  
将代码编辑通过后执行以下命令:
java -Djava.security.auth.login.config==jaas.config com.SimpleLogin


你可能感兴趣的:(AS)