Tomcat JAAS 身份验证和授权

ava 认证和授权服务(JAAS)是一种用于验证用户身份以确定安全等级的 Tomcat Realm ( org.apache.catalina.Realm)的实现。

需求

Tomcat 7.0, MVC (推荐 Spring MVC)和数据库(推荐 Mysql)

1. 配置

appName

appName 属性的值将被传递给 LoginContext (javax.security.auth.login.LoginContext) 构造函数,以指定实现LoginModule ( javax.security.auth.spi.LoginModule) 的实体名称。

LoginModule 是一个提供了特定类型的身份验证的可插拔接口。 LoginContext 通过读取配置(javax.security.auth.login.Configuration) 指定登录程序中的登录模块(S)。

K6F
K6F
翻译于 3年前

0人顶

 翻译的不错哦!

一个登录配置包括以下信息 :

?
1
2
3
4
5
Name {
        ModuleClass  Flag    ModuleOptions;
        ModuleClass  Flag    ModuleOptions;
        ModuleClass  Flag    ModuleOptions;
  };

一个登录配置中可能包括不只一个的登录模块。

ModuleClass 是登录模块的完整相称类名。Flag 值 ( Required, Requisite, Sufficient, Optional ) 则控制身份验证的行为。

ModuleOptions则直接将值传递给底层登录模块,它的格式是一个用空格分割的列表。

将下列 Tomcat JAAS Realm 配置添加到 Tomcat server.xml 文件中:

?
1
2
3
< realm classname = "org.apache.catalina.realm.JAASRealm" appname = "jasslogin" userclassnames = "com.test.secure.TestUserPrincipal" roleclassnames = "com.test.secure.TestRolePrincipal" >
  
</ realm >

在 tomcat/conf 文件夹中创建 jass.config 文件:

?
1
2
3
jasslogin{
com.test.secure.TestLoginModule  required;
};

在 tomcat/bin 文件夹中创建 setenv.bat 文件,并添加下列配置:

?
1
set JAVA_OPTS=-Djava.security.auth.login.config==C:/tomcat/conf/jaas.config
K6F
K6F
翻译于 3年前

0人顶

 翻译的不错哦!

其它翻译版本(1)

2. 登录模块

当 logincontext 读取配置时,登录模块将初始化,包括 Subject ( javax.security.auth.Subject),回叫处理(javax.security.auth.callback.CallBackHandler),共享登录模块以及 LoginModule-specific 选项。

?
1
boolean login()  throws LoginException;

第一个被 LoginContext 调用来实际处理身份验证的方法是 Login 方法,它将返回 true 或 false 。如果验证成功,commit 方法将被调用。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
package com.test.secure;
 
import java.io.IOException;
import java.security.Principal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
 
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
 
import org.apache.log4j.Logger;
 
public class TestLoginModule  implements LoginModule {
 
     Logger logger = Logger.getLogger(TestLoginModule. class );
     public static String USER_QUERY =  "select user_name from users where user_name=? and user_pass=?" ;
     public static String ROLE_QUERY =  "select role_name from  user_roles where user_name=?" ;
 
     private Subject subject;
     private CallbackHandler callbackHandler;
     private Map sharedState;
     private Map options;
 
     // configurable option
     private boolean debug =  false ;
 
     // the authentication status
     private boolean succeeded =  false ;
     private boolean commitSucceeded =  false ;
 
     // user credentials
     private String username =  null ;
     private char [] password =  null ;
     // principals
     private TestUserPrincipal testUserPrincipal;
     private TestRolePrincipal testRolePrincipal;
     private TestPasswordPrincipal testPasswordPrincipal;
 
     @Override
     public void initialize(Subject subject, CallbackHandler callbackHandler,
             Map<String, ?> sharedState, Map<String, ?> options) {
 
         this .subject = subject;
         this .callbackHandler = callbackHandler;
         this .sharedState = sharedState;
         this .options = options;
 
     }
 
     @Override
     public boolean login()  throws LoginException {
 
         if (callbackHandler ==  null ) {
             throw new LoginException( "call back handler is null" );
         }
 
         Callback[] callbacks =  new Callback[ 2 ];
         callbacks[ 0 ] =  new NameCallback( "username" );
         callbacks[ 1 ] =  new PasswordCallback( "password: " false );
 
         try {
 
             callbackHandler.handle(callbacks);
             
             username = ((NameCallback) callbacks[ 0 ]).getName();
             password = ((PasswordCallback) callbacks[ 1 ]).getPassword();
 
             if (username ==  null || password ==  null ) {
                 throw new LoginException(
                         "Callback handler does not return login data properly" );
 
             }
 
             logger.info( " username" + username);
             logger.info( "password" + password);
 
             // authenticate
 
             if (isValidUser()) {
                 succeeded =  true ;
                 return true ;
             }
             
         
 
         catch (IOException e) {
             e.printStackTrace();
         catch (UnsupportedCallbackException e) {
             e.printStackTrace();
         }
 
         return false ;
     }
 
     @Override
     public boolean commit()  throws LoginException {
         
         logger.info( "committing..." );
 
         if (succeeded ==  false ) {
             return false ;
         else {
             testUserPrincipal =  new TestUserPrincipal(username);
             
             
             if (!subject.getPrincipals().contains(testUserPrincipal)) {
                 subject.getPrincipals().add(testUserPrincipal);
                 
             }
             
             
         /*  testPasswordPrincipal = new TestPasswordPrincipal(new String(
                     password));
             if (!subject.getPrincipals().contains(testPasswordPrincipal)) {
                 subject.getPrincipals().add(testPasswordPrincipal);
                 
             }
*/
             // populate subject with roles.
             
             
             // strings
             List roles = getRoles(testUserPrincipal);
             
             
             
             for (String role : roles) {
                 
                 
                 
                 testRolePrincipal =  new TestRolePrincipal(role);
                 
                 if (!subject.getPrincipals().contains(testRolePrincipal)) {
                     
                     subject.getPrincipals().add(testRolePrincipal);
                     
                 }
                     
                     
                 
             }
             
             
             commitSucceeded =  true ;
 
             logger.info( "Login subject were successfully populated with principals and roles" );
             logger.info( "--------------principals" );
             logger.info(subject.getPrincipals());
                 
            
             
             for (Principal p: subject.getPrincipals()){
                 
                 if (p  instanceof TestRolePrincipal){
                     
                     logger.info( " ROLE: " +p.getName());
                     
                 }
                 
                 
             }
             
             
             
 
             return true ;
         }
     }
 
     @Override
     public boolean abort()  throws LoginException {
 
         if (succeeded ==  false ) {
             return false ;
         else if (succeeded ==  true && commitSucceeded ==  false ) {
             succeeded =  false ;
             username =  null ;
             if (password !=  null ) {
                 password =  null ;
             }
             testUserPrincipal =  null ;
         else {
             logout();
         }
         return true ;
     }
 
     @Override
     public boolean logout()  throws LoginException {
 
         subject.getPrincipals().remove(testUserPrincipal);
         succeeded =  false ;
         succeeded = commitSucceeded;
         username =  null ;
         if (password !=  null ) {
             for ( int i =  0 ; i < password.length; i++) {
                 password[i] =  ' ' ;
                 password =  null ;
             }
         }
         testUserPrincipal =  null ;
         return true ;
     }
 
     private boolean isValidUser()  throws LoginException {
 
         Connection connection =  null ;
 
         ResultSet rs =  null ;
         PreparedStatement stmt =  null ;
 
         try {
 
             connection = getConnection();
 
             stmt = connection.prepareStatement(USER_QUERY);
             stmt.setString( 1 , username);
             stmt.setString( 2 new String(password));
 
             rs = stmt.executeQuery();
 
             if (rs.next()) {  // User exist with the given user name and
                                 // password.
                 return true ;
             }
         catch (Exception e) {
             logger.error( "Error when loading user from the database " + e);
             e.printStackTrace();
         finally {
             try {
                 rs.close();
             catch (SQLException e) {
                 logger.error( "Error when closing result set." + e);
             }
             try {
                 stmt.close();
             catch (SQLException e) {
                 logger.error( "Error when closing statement." + e);
             }
             try {
                 connection.close();
             catch (SQLException e) {
                 logger.error( "Error when closing connection." + e);
             }
         }
         return false ;
     }
 
     private List getRoles(TestUserPrincipal user) {
 
         Connection connection =  null ;
 
         ResultSet rs =  null ;
         PreparedStatement stmt =  null ;
 
         List roleList =  new ArrayList();
 
         try {
 
             connection = getConnection();
 
             stmt = connection.prepareStatement(ROLE_QUERY);
             stmt.setString( 1 , username);
 
             rs = stmt.executeQuery();
 
             while (rs.next()) {
                 roleList.add(rs.getString( "role_name" ));
                 user.addRole( new TestRolePrincipal((rs.getString( "role_name" ))));
             }
         catch (Exception e) {
             logger.error( "Error when loading user from the database " + e);
             e.printStackTrace();
         finally {
             try {
                 rs.close();
             catch (SQLException e) {
                 logger.error( "Error when closing result set." + e);
             }
             try {
                 stmt.close();
             catch (SQLException e) {
                 logger.error( "Error when closing statement." + e);
             }
             try {
                 connection.close();
             catch (SQLException e) {
                 logger.error( "Error when closing connection." + e);
             }
         }
         
         return roleList;
     }
 
     private Connection getConnection() {
 
         try {
             Class.forName( "com.mysql.jdbc.Driver" );
             return DriverManager.getConnection(
                     "jdbc:mysql://localhost:3306/test" "root" "password" );
         catch (Exception e) {
             e.printStackTrace();
         }
         return null ;
     }
 
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
package com.test.secure;
 
import java.security.Principal;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
 
import org.apache.catalina.Group;
import org.apache.catalina.Role;
import org.apache.catalina.User;
import org.apache.catalina.UserDatabase;
 
public class TestUserPrincipal  implements User {
     
     
     private String username;
     private Set roles =  new HashSet();
     
     public TestUserPrincipal(String u){
         this .username=u;
     }
 
     @Override
     public String getName() {
         // TODO Auto-generated method stub
         return  username;
     }
 
     @Override
     public void addGroup(Group arg0) {
         // TODO Auto-generated method stub
         
     }
 
     @Override
     public void addRole(Role role) {
     roles.add(role);
         
     }
 
     @Override
     public String getFullName() {
         // TODO Auto-generated method stub
         return username;
     }
 
     @Override
     public Iterator getGroups() {
         
         
         
         return null ;
     }
 
     @Override
     public String getPassword() {
         // TODO Auto-generated method stub
         return null ;
     }
 
     @Override
     public Iterator getRoles() {
 
         return roles.iterator();
     }
 
     @Override
     public UserDatabase getUserDatabase() {
         // TODO Auto-generated method stub
         return null ;
     }
 
     @Override
     public String getUsername() {
         // TODO Auto-generated method stub
         return username;
     }
 
     @Override
     public boolean isInGroup(Group arg0) {
         // TODO Auto-generated method stub
         return false ;
     }
 
     @Override
     public boolean isInRole(Role role) {
         
         if ( 1 == 1 ){
             return true ;
         }
         
         if (!roles.isEmpty()){
             Iterator it =roles.iterator();
             while (it.hasNext()){
             Role rol =(Role)it.next();
             if (rol.getName()!= null && rol.getName().equals(role.getName())){
                 return true ;
             }
             }
         }
         
         return false ;
     }
 
     @Override
     public void removeGroup(Group arg0) {
         // TODO Auto-generated method stub
         
     }
 
     @Override
     public void removeGroups() {
         // TODO Auto-generated method stub
         
     }
 
     @Override
     public void removeRole(Role arg0) {
         // TODO Auto-generated method stub
         
     }
 
     @Override
     public void removeRoles() {
         roles.clear();
         
     }
 
     @Override
     public void setFullName(String arg0) {
         setUsername(username);
         
     }
 
     @Override
     public void setPassword(String arg0) {
         // TODO Auto-generated method stub
         
     }
 
     @Override
     public void setUsername(String arg0) {
      this .username=arg0;
         
     }
 
     
     
}
 
 
package com.test.secure;
 
import java.io.Serializable;
 
import java.security.Principal;
 
import org.apache.catalina.Role;
import org.apache.catalina.UserDatabase;
 
public class TestRolePrincipal  implements Role, Serializable {
     
     
     private String roleName;
     
     
     public TestRolePrincipal(String name){
         this .roleName=name;
     }
 
     @Override
     public String getName() {
         // TODO Auto-generated method stub
         return getRolename();
     }
 
     @Override
     public String getDescription() {
         // TODO Auto-generated method stub
         return " some role" ;
     }
 
     @Override
     public String getRolename() {
         // TODO Auto-generated method stub
         return roleName;
     }
 
     @Override
     public UserDatabase getUserDatabase() {
         // TODO Auto-generated method stub
         return null ;
     }
 
     @Override
     public void setDescription(String arg0) {
         
         
     }
 
     @Override
     public void setRolename(String arg0) {
         roleName =arg0;
         
     }
 
 
    

你需要将 tomcat/lib 中的三个类都封装到 jar 中,一边在启动时加载。

K6F
K6F
翻译于 3年前

0人顶

 翻译的不错哦!

登录处理器

在这个例子中我们使用的是 Spring MVC,但作为测试,你可使用任何其他的请求处理器,或者只是一个 Servlet:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.test.secure;
 
import java.security.Principal;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
 
import org.apache.catalina.Session;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
 
public class SecureController  extends AbstractController {
 
     @Override
     protected ModelAndView handleRequestInternal(HttpServletRequest req,
             HttpServletResponse res)  throws Exception {
 
  
         
    
         
     ModelAndView m =  new ModelAndView( "SecureView" );
     return m;
     }
 
}

5. 安全约束

在 web.xml 中增加一个安全约束 ( org.apache.catalina.deploy. SecurityConstraint) 和角色授权的资源访问:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
security-constraint >
  
  web-resource-collection >
  web-resource-name >interdit< / web-resource-name >
  url-pattern >/go/*< / url-pattern >
  < / web-resource-collection >
  
  auth-constraint >
  description >tomcat< / description >
  role-name >tomcat< / role-name >
  < / auth-constraint >
 
< / security-constraint >

然后添加登录和登录错误页

?
1
FORMjasslogin/join.do/joinerror.do

红薯
红薯
翻译于 3年前

0人顶

 翻译的不错哦!

6. 用户密码和角色
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE TABLE `users` (
   `user_name`  varchar (15)  NOT NULL ,
   `user_pass`  varchar (15)  NOT NULL ,
   PRIMARY KEY (`user_name`);
 
INSERT INTO `users`  VALUES ( 'admin' , 'root' ),( 'role1' , 'root' ),( 'tomcat' , 'tomcat' );
 
 
CREATE TABLE `user_roles` (
   `user_name`  varchar (15)  NOT NULL ,
   `role_name`  varchar (15)  NOT NULL ,
   PRIMARY KEY (`user_name`,`role_name`);
 
 
INSERT INTO `user_roles`  VALUES ( 'tomcat' , 'manager-gui' ),( 'tomcat' , 'manager-jmx' ),( 'tomcat' , 'manager-script' ),( 'tomcat' , 'manager-status' ),( 'tomcat' , 'tomcat' );

登录表单

?
1
2
3
4
5
6
7
8
9
10
< form action = "<%= response.encodeURL(" j_security_check")="" %="">" method="post">
  
     < fieldset >
         < legend >Login </ legend >
         < p >< label for = "name" >Username</ label > < input name = "j_username" type = "text" ></ p >
         < p >< label for = "e-mail" >Password</ label > < input name = "j_password" type = "password" >< br ></ p >
         < p class = "submit" >< input value = "Submit" type = "submit" ></ p >
     </ fieldset >
  
</ form >
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值