运行环境:WebLogic Server 12c + Oracle Database XE 10gR2
发现有很多人问如何为WebLogic Server配置基于数据库的认证方式,大概是还是因为数据库比LDAP好操作,好控制。
本来以为这个问题很简单,但查找了很多资料,居然没有详细的说明,包括WebLogic的官方文档也只是说可以配置,但没有具体说明如何配。
直到我找到了参考文献1的这篇文章。
以下内容基本来自这篇文章的翻译和整理。
重点步骤说明:
1. 创建JHS Schema
当然,你可以修改成其它名称的Schema。
2. 在JHS Schema下创建Table和数据
执行如下SQL语句:
CREATE TABLE JHS_ROLES ( ID NUMBER(*, 0) NOT NULL, ORG_KEY VARCHAR2(30) DEFAULT 'DEFAULT' NOT NULL, SHORT_NAME VARCHAR2(10) NOT NULL, NAME VARCHAR2(40) NOT NULL ); CREATE TABLE JHS_USER_ROLE_GRANTS ( ID NUMBER(*, 0) NOT NULL, USR_ID NUMBER(*, 0) NOT NULL, RLE_ID NUMBER(*, 0) NOT NULL ); CREATE TABLE JHS_USERS ( ID NUMBER(*, 0) NOT NULL, EMAIL_ADDRESS VARCHAR2(240), USERNAME VARCHAR2(240) NOT NULL, ORG_KEY VARCHAR2(30) DEFAULT 'DEFAULT', PASSWORD VARCHAR2(240), DISPLAY_NAME VARCHAR2(240), LOCALE VARCHAR2(10) ); ALTER TABLE JHS_ROLES ADD CONSTRAINT JHS_RLE_PK PRIMARY KEY ( ID ) ENABLE; ALTER TABLE JHS_ROLES ADD CONSTRAINT JHS_RLE_UK1 UNIQUE ( SHORT_NAME,ORG_KEY ) ENABLE; ALTER TABLE JHS_USER_ROLE_GRANTS ADD CONSTRAINT JHS_URG_PK PRIMARY KEY ( ID ) ENABLE; ALTER TABLE JHS_USER_ROLE_GRANTS ADD CONSTRAINT JHS_URG_UK1 UNIQUE ( RLE_ID, USR_ID ) ENABLE; ALTER TABLE JHS_USERS ADD CONSTRAINT JHS_USR_PK PRIMARY KEY ( ID ) ENABLE; CREATE SEQUENCE JHS_SEQ INCREMENT BY 1 MAXVALUE 999999999999999999999999999 MINVALUE 1 CACHE 20 ; -- Create two users SKING and AHUNOLD insert into jhs_users (ID, EMAIL_ADDRESS, USERNAME, ORG_KEY, PASSWORD, DISPLAY_NAME) select jhs_seq.nextval,'SKING','SKING','DEFAULT','SKING', 'Steven King' from dual where not exists (select '1' from jhs_users where username='SKING'); insert into jhs_users (ID, EMAIL_ADDRESS, USERNAME, ORG_KEY, PASSWORD, DISPLAY_NAME) select jhs_seq.nextval,'AHUNOLD','AHUNOLD','DEFAULT','AHUNOLD', 'Alexander Hunold' from dual where not exists (select '1' from jhs_users where username='AHUNOLD'); -- set up two roles: Administrator and User insert into jhs_roles(id, SHORT_NAME, name) select jhs_seq.nextval, 'ADMIN','Administrator' from dual where not exists (select '1' from jhs_roles where short_name='ADMIN'); insert into jhs_roles(id, SHORT_NAME, name) select jhs_seq.nextval, 'USER','User' from dual where not exists (select '1' from jhs_roles where short_name='USER'); -- Make Steven King Administrator insert into jhs_user_role_grants (id,rle_id,usr_id) select jhs_seq.nextval, rle.id, usr.id from jhs_roles rle, jhs_users usr where rle.short_name='ADMIN' and usr.username='SKING' and not exists (select '1' from jhs_user_role_grants urg2 where urg2.usr_id = usr.id and urg2.rle_id = rle.id); -- Make Alexander Hunold User insert into jhs_user_role_grants (id,rle_id,usr_id) select jhs_seq.nextval, rle.id, usr.id from jhs_roles rle, jhs_users usr where rle.short_name='USER' and usr.username='AHUNOLD' and not exists (select '1' from jhs_user_role_grants urg2 where urg2.usr_id = usr.id and urg2.rle_id = rle.id); commit;
3. 创建jhsDS DataSource
4. 创建Database Authenticator Provider
切换到Provider->Authentication Tab:
新增一个Authenticator,注意,Type要选择 SQLAuthenticator。
设置Control Flag为SUFFICIENT。
注意,DataSource Name指向的是JHS Data Source,而不是JNDI Name:jhsDS;Password使用Plain风格,最后别忘了点击Save按钮。
接着,还要指明如何通过SQL语句获取User、Group、Role。
为了简单,这里直接修改[domain_name]\config\config.xml文件,当然,也可以通过WLS Console修改。
修改前的DatabaseAuthenticator配置如下:
<sec:authentication-provider xsi:type="wls:sql-authenticatorType"> <sec:name>DatabaseAuthenticator</sec:name> <sec:control-flag>SUFFICIENT</sec:control-flag> <wls:data-source-name>jhsDS</wls:data-source-name> <wls:plaintext-passwords-enabled>true</wls:plaintext-passwords-enabled> <wls:password-style>PLAINTEXT</wls:password-style> </sec:authentication-provider>
修改后的DatabaseAuthenticator配置如下:
<sec:authentication-provider xsi:type="wls:sql-authenticatorType"> <sec:name>DatabaseAuthenticator</sec:name> <sec:control-flag>SUFFICIENT</sec:control-flag> <wls:data-source-name>JHS Data Source</wls:data-source-name> <wls:plaintext-passwords-enabled>true</wls:plaintext-passwords-enabled> <wls:sql-get-users-password>SELECT password FROM jhs_users WHERE username = ?</wls:sql-get-users-password> <wls:sql-user-exists>SELECT username FROM jhs_users WHERE username = ?</wls:sql-user-exists> <wls:sql-list-member-groups>SELECT short_name FROM jhs_user_role_grants g ,jhs_roles r,jhs_users u WHERE g.usr_id = u.id and g.rle_id = r.id and u.username = ?</wls:sql-list-member-groups> <wls:sql-list-users>SELECT username FROM jhs_users WHERE username LIKE ?</wls:sql-list-users> <wls:sql-get-user-description>SELECT display_name FROM jhs_users WHERE username = ?</wls:sql-get-user-description> <wls:sql-list-groups>SELECT short_name FROM jhs_roles WHERE short_name LIKE ?</wls:sql-list-groups> <wls:sql-group-exists>SELECT short_name FROM jhs_roles WHERE short_name = ?</wls:sql-group-exists> <wls:sql-is-member>SELECT u.username FROM jhs_user_role_grants g ,jhs_users u WHERE u.id = g.usr_id and rle_id = ( select id from jhs_roles where short_name = ? ) AND usr_id = ( select id from jhs_users where username = ? )</wls:sql-is-member> <wls:sql-get-group-description>SELECT name FROM jhs_roles WHERE short_name = ?</wls:sql-get-group-description> <wls:password-style>PLAINTEXT</wls:password-style> <wls:sql-create-user>INSERT INTO jhs_users ( id,username , password , display_name) VALUES (jhs_seq.nextval, ? , ? , ? )</wls:sql-create-user> <wls:sql-remove-user>DELETE FROM jhs_users WHERE username = ?</wls:sql-remove-user> <wls:sql-remove-group-memberships>DELETE FROM jhs_user_role_grants WHERE rle_id = ( select id from jhs_roles where short_name = ? ) or usr_id = ( select id from jhs_users where username = ? )</wls:sql-remove-group-memberships> <wls:sql-set-user-description>UPDATE jhs_users SET display_name = ? WHERE username = ?</wls:sql-set-user-description> <wls:sql-set-user-password>UPDATE jhs_users SET password = ? WHERE username = ?</wls:sql-set-user-password> <wls:sql-create-group>insert into jhs_roles(id, short_name, name) values (jhs_seq.nextval, ?, ?)</wls:sql-create-group> <wls:sql-set-group-description>UPDATE jhs_roles SET name = ? WHERE short_name = ?</wls:sql-set-group-description> <wls:sql-add-member-to-group>INSERT INTO jhs_user_role_grants (id,rle_id,usr_id) VALUES( jhs_seq.nextval , ( select id from jhs_roles where short_name = ?),(select id from jhs_users where username = ?))</wls:sql-add-member-to-group> <wls:sql-remove-member-from-group>DELETE FROM jhs_user_role_grants WHERE rle_id = ( select id from jhs_roles where short_name = ? ) AND usr_id = ( select id from jhs_users where username = ? )</wls:sql-remove-member-from-group> <wls:sql-remove-group>DELETE FROM jhs_roles WHERE short_name = ?</wls:sql-remove-group> <wls:sql-remove-group-member>DELETE FROM jhs_user_role_grants WHERE rle_id = ( select id from jhs_roles where short_name = ? )</wls:sql-remove-group-member> <wls:sql-list-group-members>SELECT username FROM jhs_user_role_grants g ,jhs_roles r,jhs_users u WHERE g.usr_id = u.id and g.rle_id = r.id and r.short_name = ? and u.username like ?</wls:sql-list-group-members> </sec:authentication-provider>
5. 重启WebLogic,应该能看到Database中的用户和组。
用户:AHUNOLD和SKING
组:ADMIN和USER
把新增的Database Authentication provider Reorder到最上面。
因为默认的Default Authentication provider 的Control Flag 是Required,因此会首先从这里验证用户,验证不通过则宣告认证失败。
为了让Database Authenticator能够首先验证用户,需要把Database Authentication provider放到最上面。
6. 测试
在WLS Console中,可以直接为Database Authentication provider 创建用户和组。
创建的用户和组将会写到JHS Schema指定的数据库表中。
(1)创建用户GuoLiJie。
(2)创建组managers。
(3)把GuoLiJie放到组managers中。
发布timeoff.war,访问http://localhost:7001/timeoff/managers/officeclosing.html。
输入用户GuoLiJie/welcome1,应该能够验证通过看到下个页面。
7. 加密用户口令
以上的设置用户的口令是以明文保存在数据库表JHS_USERS中的,这当然不够安全。
在Database Authentication provider中的Specific配置Tab中,有如下属性可以设置:
(1)Plaintext Passwords Enabled:true/false。
true:WLS将从数据库表中读取passwords,并直接和用户输入的密码进行比较,即认为数据库表中保存的是明文。
这是我们现在使用的方式。
false:WLS认为数据库表中保存的是密文,将会把用户输入的密码加密后在进行比较。
我们将在后面测试该选项。
(2)Password Style Retained:true/false。
当WLS写入口令到数据库表时,会根据口令的加密算法生成密文,同时在前面加上一个算法前缀:如{SHA-1}W6PH5MM5PZ8GGIULBPGZG37MJ9G= 。
true:当用户设置(新增或修改)口令时,继续使用原密文使用的加密算法(根据前缀来判断使用的是哪种加密算法)。
false:当用户设置(新增或修改)口令时,使用Password Algorithm设置的算法重新计算密文。
(3)Password Algorithm:默认SHA-1。还可以是MD2,MD5。
更多值请参考http://java.sun.com/javase/6/docs/technotes/guides/security/StandardNames.html#algspec。
(4)Password Style:可以为PLAINTEXT,HASHED,SALTEDHASHED。
PLAINTEXT:明文。
HASHED:密文,但同一密码生成的密文相同,容易被破解。
SALTEDHASHED:加盐Hash,即使是同一密码生成的密文也不相同,不容易被破解。
8. 测试加密后的用户口令
(1)把数据库中的口令以密文方式保存。
为此设置如下:
Plaintext Passwords Enabled=false
Password Style Retained=false
Password Algorithm:SHA-1
Password Style:HASHED
增加用户Test、Test2,并修改GuoLiJie的口令,这里口令都设置为welcome1。
注意,口令都被加密了,但是同样的口令加密后的密文都是一样的:{SHA-1}41vs5sXm4OhspR0EQOkigqnWrIo=。
(2)设置Password Style:SALTEDHASHED,其余的设置与(1)相同。
修改用户Test、Test2、GuoLiJie的口令,所有口令还是设置为welcome1。
再次查看数据库表中口令值,发现虽然口令都是一样的,但是加密后的密文完全不一样。
重新打开一个浏览器,访问http://localhost:7001/timeoff/managers/officeclosing.html。
输入用户GuoLiJie/welcome1,应该能够验证通过看到下个页面,这说明口令加密后工作正常。
可以看出,不论选择哪种加密算法,WLS都会帮你做认证,无需开发人员做额外的加解密工作,这个真是方便啊。
参考文献:
1. http://biemond.blogspot.com/2008/12/using-database-tables-as-authentication.html
2. http://chrismuir.sys-con.com/node/1130973/mobile
3. http://java.sun.com/javase/6/docs/technotes/guides/security/StandardNames.html#algspec
没有评论:
发表评论