【JBoss】3. JBoss SX安全框架

来源:互联网 发布:网络兼职论坛发帖 编辑:程序博客网 时间:2024/06/05 20:39

JBoss SX

JBoss使用JBoss SX框架来确保应用程序安全。它建立在Java身份验证和授权服务的顶层(JAAS,Java Authentication and Authorization Service)。

当JBoss接收到请求时,目标应用程序不需要知道基本安全数据库的位置或访问方式;

请求被传递到名为“安全域”的JBoss SX组件中,这是一种用来保护所有对组件的球球的抽象;

安全域执行所有必要的安全检查并告知组件用户可否继续进行访问,安全域知道如何使用一个或多个登录模块从数据源加载安全数据;


安全域

可以在server/x/conf/login-config.xml中添加或更改现有安全域定义。

<application-policy>定义一个安全域,JBoss SX根据name生成JNDI上下文,并使用该上下文将安全域绑定到JNDI中;

<login-module>定义登录模块,登录模块可以从属性文件、或数据库中加载安全信息(密码、角色)。


<!--application-policy:定义安全域--><application-policy name="authnservice">  <authentication>    <!--login-module:定义登录模块-->    <login-module code="com.alpha.security.authentication.TokenLoginModule" flag="required"/>    <login-module code="com.alpha.security.authentication.LockedAccountLoginModule" flag="required">       <module-option name="dsJndiName">java:/OracleDS</module-option>       <module-option name="lockingQuery">          SELECT 。。。       </module-option>       <module-option name="updateLocked">          UPDATE USER 。。。       </module-option>       <module-option name="updateFailLoginCount">          UPDATE USER 。。。       </module-option>    </login-module>    <login-module code="com.alpha.security.authentication.TokenServiceLoginModule" flag="required">       <module-option name="unauthenticatedIdentity">guest</module-option>       <module-option name="dsJndiName">java:/OracleDS</module-option>       <module-option name="hashAlgorithm">SHA-1</module-option>       <module-option name="hashEncoding">hex</module-option>       <module-option name="principalsQuery">                select PASSWORDfrom 。。。      </module-option>      <module-option name="rolesQuery">               SELECT Roles FROM ROLE r,。。。      </module-option>      <module-option name="password-stacking">useFirstPass</module-option>      <module-option name="rolePrefix">alpha/</module-option>      <module-option name="hashCharset">UTF-8</module-option>   </login-module>   <login-module code="com.alpha.security.authentication.PasswordExpirationLoginModule" flag="required">      <module-option name="dsJndiName">java:/OracleDS</module-option>      <module-option name="passwordQuery">         select date_of_creation, date_of_expiration from (select pw.*  from sec_password pw, sec_user uwhere u.login_name = UPPER(?)  and pw.user_id = u.id   order by pw.date_of_creation desc)  where rownum=1      </module-option>      <module-option name="checkEnabledQuery">          select v.boolean_value  from config_key k, config_value v   where k.key = 'Options.system.settings.pwExpireEnabled'and v.key = k.id      </module-option>      <module-option name="checkFirstLoginQuery">          select v.boolean_value  from config_key k, config_value v   where k.key = 'Options.system.settings.enableFirstLogin'and v.key = k.id      </module-option>      <module-option name="passAgeQuery">          select v.integer_value  from config_key k, config_value v   where k.key = 'Options.system.settings.pwExpireAge'and v.key = k.id      </module-option>      <module-option name="notifyPeriodQuery">          select v.integer_value  from config_key k, config_value v   where k.key = 'Options.system.settings.pwNotifyPeriod'and v.key = k.id      </module-option>   </login-module>   <login-module code="com.alpha.security.authentication.RoleMappingLoginModule" flag="required">      <module-option name="mapping">          。。。      </module-option>   </login-module>   <login-module code="com.alpha.security.authentication.TokenCreatingLoginModule" flag="required"/></authentication></application-policy>

JMX查看安全域

jboss.security - service=XMLLoginConfig


displayAppConfig( "authnservice" )


安全域信息:


登录模块UsersRolesLoginModule

登录模块可以从属性文件、或数据库中加载安全信息(密码、角色)。

前面的例子中,登录模块是自定义的。

JBoss SX提供了多个登录模块,其中UsersRolesLoginModule用于在属性文件中存储用户名和角色信息。

  <application-policy name="JBossWS">    <authentication>      <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required">        <module-option name="usersProperties">props/jbossws-users.properties</module-option>        <module-option name="rolesProperties">props/jbossws-roles.properties</module-option>        <module-option name="unauthenticatedIdentity">anonymous</module-option>      </login-module>    </authentication>  </application-policy>

这种登录模块常用于开发和测试。


登录模块DatabaseServerLoginModule

DatabaseServerLoginModule用于在数据库中存储用户名和角色信息:

<login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required">    <module-option name="password-stacking">useFirstPass</module-option>    <module-option name="dsJndiName">java:/pacsDS</module-option>    <module-option name="principalsQuery">select passwd from users where user_id=?</module-option>    <module-option name="rolesQuery">select roles from roles where user_id=?</module-option>    <module-option name="hashEncoding">base64</module-option>    <module-option name="hashCharset">UTF-8</module-option>    <module-option name="hashAlgorithm">SHA-1</module-option></login-module>
<dsJndiName>定义了数据源的JNDI名称。

自定义登录模块

继承javax.security.auth.spi.LoginModule


import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Timestamp;import java.util.Map;import javax.security.auth.Subject;import javax.security.auth.callback.CallbackHandler;import javax.security.auth.login.AccountExpiredException;import javax.security.auth.login.LoginException;import javax.security.auth.spi.LoginModule;import org.apache.log4j.Logger;import org.jboss.security.SecurityContextAssociation;public class PasswordExpirationLoginModule implements LoginModule {private static final Logger log = Logger.getLogger(PasswordExpirationLoginModule.class);private final class PasswordDao extends LoginModuleDAO {private final String userName;Timestamp expireDate;Timestamp createDate;private PasswordDao(String userName) {super(dsJndiName);this.userName = userName;}@Overridepublic void innerRun(Connection conn, PreparedStatement ps, ResultSet rs) throws SQLException,LoginException {ps = conn.prepareStatement(passwordQuery);ps.setString(1, userName);rs = ps.executeQuery();if (rs.next()) {expireDate = rs.getTimestamp("date_of_expiration");createDate = rs.getTimestamp("date_of_creation");}}}private final class SettingDAO<T> extends LoginModuleDAO {private final String query;private T data;private final Class<T> type;private SettingDAO(String query, Class<T> type) {super(dsJndiName);this.query = query;this.type = type;}@Overridepublic void innerRun(Connection conn, PreparedStatement ps, ResultSet rs) throws SQLException,LoginException {ps = conn.prepareStatement(query);rs = ps.executeQuery();if (rs.next()) {if(type==Integer.class) {data = (T) Integer.valueOf(rs.getInt(1));}else if(type==Boolean.class) {data = (T) Boolean.valueOf(rs.getBoolean(1));}else if(type==Timestamp.class) {data = (T) rs.getTimestamp(1);}else {data = (T) rs.getObject(1);}}}public T getResult() {return data;}}/** * Flag to allow ignore "about to expire" checking  */public static final String IGNORE_EXPIRED = "ignore_expired";//mili seconds in a dayprivate static final long timeADay = 86400000L;private String dsJndiName;//get pw creation date and expiration dateprivate String passwordQuery;private String checkEnabledQuery;private String checkFirstLoginQuery;private String notifyPeriodQuery;private String passAgeQuery;private CallbackHandler callbackHandler;private CallbackHelper helper = new CallbackHelper();        @Overridepublic void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState,Map options) {this.callbackHandler = callbackHandler;dsJndiName = (String) options.get("dsJndiName");passwordQuery = (String) options.get("passwordQuery");checkEnabledQuery = (String) options.get("checkEnabledQuery");checkFirstLoginQuery = (String) options.get("checkFirstLoginQuery");notifyPeriodQuery = (String) options.get("notifyPeriodQuery");passAgeQuery = (String) options.get("passAgeQuery");}        @Overridepublic boolean login() throws LoginException {if(log.isDebugEnabled()) {log.debug("do expire check");}final String userName =  helper.getUsername(callbackHandler);PasswordDao dao = new PasswordDao(userName);dao.run();if(isCheckFirstLoginEnabled()) {if(dao.expireDate!=null && dao.expireDate.equals(dao.createDate)) {throw new FirstLoginException();}}if(isCheckEnabled()) {long passAge = getPassAge() * timeADay;SettingDAO<Timestamp> timeDao = new SettingDAO<Timestamp>("select systimestamp from dual", Timestamp.class);timeDao.run();Timestamp now = timeDao.getResult();if(dao.expireDate!=null) {log.warn("expiration date has been set for current password.");long time = dao.expireDate.getTime() - dao.createDate.getTime();if(time>0) {passAge = Math.min(passAge, time);}}long currentAge = now.getTime() - dao.createDate.getTime();if(currentAge >= passAge) {throw new AccountExpiredException();}//ignore about to expireBoolean isIgnore = (Boolean)(SecurityContextAssociation                                          .getSecurityContext().getData().get(IGNORE_EXPIRED));if(isIgnore!=null && isIgnore) {return false;}long notifiPeriod = getNotifyPeriod() * timeADay;if(currentAge >= passAge - notifiPeriod) {long time = passAge -currentAge;int day = (int)(time / timeADay + (time % timeADay==0 ? 0 : 1));throw new AccountToExpireException(day);}}return false;}private boolean isCheckFirstLoginEnabled() throws LoginException {SettingDAO<Boolean> dao = new SettingDAO(checkFirstLoginQuery, Boolean.class);dao.run();Boolean result = dao.getResult();return result;}private int getNotifyPeriod() throws LoginException{SettingDAO<Integer> dao = new SettingDAO(notifyPeriodQuery, Integer.class);dao.run();Integer data = dao.getResult();if(data==null) {log.warn("setting for notify period is not found, use hardcode value 14");return 14;}return data;}private int getPassAge() throws LoginException {SettingDAO<Integer> dao = new SettingDAO(passAgeQuery, Integer.class);dao.run();Integer data = dao.getResult();if(data==null) {log.warn("setting for password expired age is not found");return 42;}return data;}private boolean isCheckEnabled() throws LoginException{SettingDAO<Boolean> dao = new SettingDAO(checkEnabledQuery, Boolean.class);dao.run();Boolean result = dao.getResult();return result;}        @Overridepublic boolean commit() throws LoginException {return false;}        @Overridepublic boolean abort() throws LoginException {return false;}        @Overridepublic boolean logout() throws LoginException {return false;}}













原创粉丝点击