Java EE 声明性安全性,无法为 JDBC 领域用户加载组
Posted
技术标签:
【中文标题】Java EE 声明性安全性,无法为 JDBC 领域用户加载组【英文标题】:Java EE declarative security, Cannot load group for JDBC realm user 【发布时间】:2012-05-16 00:33:01 【问题描述】:这是我在这里的第一篇文章。关于声明式 Java EE 安全性,我有两个问题:(1) 基于文件的身份验证和 (2) 基于 DB 的身份验证。我为这两个问题附上了配置的相关部分。我在 Glassfish 3.1.1 上运行代码。也提前感谢您的帮助。
我也在寻找我的问题的答案,并找到了一些有用的示例,我也将它们放在了消息的底部。我尝试关注它们,以便配置的当前状态可以包含这些示例的详细信息,但它们并没有解决问题。
-如果勾选“默认主体到角色映射”,则基于文件的身份验证可以正常工作,否则即使将主体添加到映射中,它也不起作用。我可能以不正确的方式配置了一些东西。
-基于数据库的身份验证。就授权而言,它不起作用,因为无法读取组名。请参阅下面的详细信息。身份验证工作正常,即用户被识别。我什至尝试重命名表格以避免与 Glassfish 的某些内部内容发生潜在的名称冲突......
(1) 基于文件的身份验证: 文件领域,2 个用户:用户、管理员添加并分配给组:用户和管理员 (configurations/server-config/security/realms/file -> 管理用户)
配置/服务器配置/安全 默认主体到角色映射“打勾”->它有效 默认主体到角色映射“未勾选”-> 即使将其添加到安全映射中,它也不起作用。
web.xml
[...]
<security-constraint>
<display-name>Admin Pages</display-name>
<web-resource-collection>
<web-resource-name>Protected Admin Area</web-resource-name>
<description/>
<url-pattern>/faces/admin/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
<http-method>HEAD</http-method>
<http-method>PUT</http-method>
<http-method>OPTIONS</http-method>
<http-method>TRACE</http-method>
<http-method>DELETE</http-method>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<display-name>User Pages</display-name>
<web-resource-collection>
<web-resource-name>Protected Users Area</web-resource-name>
<description/>
<url-pattern>/faces/users/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
<http-method>HEAD</http-method>
<http-method>PUT</http-method>
<http-method>OPTIONS</http-method>
<http-method>TRACE</http-method>
<http-method>DELETE</http-method>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>user</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>file</realm-name>
<form-login-config>
<form-login-page>/faces/loginForm.xhtml</form-login-page>
<form-error-page>/faces/loginError.xhtml</form-error-page>
</form-login-config>
</login-config>
[...]
glassfish-web.xml:
<glassfish-web-app>
<security-role-mapping>
<role-name>admin</role-name>
<group-name>admin</group-name>
</security-role-mapping>
<security-role-mapping>
<role-name>user</role-name>
<group-name>user</group-name>
</security-role-mapping>
</glassfish-web-app>
没有默认主体映射的记录错误:
-
没有映射到角色 [用户] 的主体。
没有映射到角色 [admin] 的委托人。
Log without the default principal mapping:
<security-role-mapping>
<role-name>admin</role-name>
<group-name>admin</group-name>
<principal-name>admin</principal-name>
</security-role-mapping>
<security-role-mapping>
<role-name>user</role-name>
<group-name>user</group-name>
<principal-name>user</principal-name>
</security-role-mapping>
没有默认主体映射的记录错误: 1. 没有映射到角色 [用户] 的主体。 2. 没有 Principals 映射到角色 [admin]。
(2)基于数据库的身份验证:
Realm在web.xml中把上面的realm改成jdbcRealm
1) m-n(用户和组表之间的多对多关系)
SEC1111,无法为 JDBC 领域用户 [tamas] 加载组。
2) 1-n 相同(用户和组表之间的一对多关系)
SEC1111,无法为 JDBC 领域用户 [tamas] 加载组。
3) 用户名和密码在同一张表中的组名
SEC1111,无法为 JDBC 领域用户 [tamas] 加载组。
领域配置: (我也试过把“Assign Groups”留空或者填“default”,但结果都是一样的。)
Image had to be omitted, summary:
JAAS context: jdbcRealm
JNDI: jdbc/securityDataSource
User Table: TBLUSERS
User Name Column: USERNAME
Password Column: PASSWORD
Group Table: TBLGROUPS
Group Name Column: GROUPNAME
Assign Groups: default
Digest Algorithm: none
m-n 关系的 DB ER 图:
图像必须省略,但作为补偿 :-) 您可以在下面找到 SQL 脚本。
SQL Script:
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';
CREATE SCHEMA IF NOT EXISTS `jdbcrealm` ;
USE `jdbcrealm` ;
-- -----------------------------------------------------
-- Table `jdbcrealm`.`TBLUSERS`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `jdbcrealm`.`TBLUSERS` ;
CREATE TABLE IF NOT EXISTS `jdbcrealm`.`TBLUSERS` (
`USERID` INT NOT NULL AUTO_INCREMENT ,
`USERNAME` VARCHAR(30) NOT NULL ,
`PASSWORD` VARCHAR(45) NOT NULL ,
UNIQUE INDEX `USERNAME_UNIQUE` (`USERNAME` ASC) ,
PRIMARY KEY (`USERID`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `jdbcrealm`.`TBLGROUPS`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `jdbcrealm`.`TBLGROUPS` ;
CREATE TABLE IF NOT EXISTS `jdbcrealm`.`TBLGROUPS` (
`GROUPID` INT NOT NULL AUTO_INCREMENT ,
`GROUPNAME` VARCHAR(30) NOT NULL ,
PRIMARY KEY (`GROUPID`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `jdbcrealm`.`USERS_GROUPS`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `jdbcrealm`.`USERS_GROUPS` ;
CREATE TABLE IF NOT EXISTS `jdbcrealm`.`USERS_GROUPS` (
`USER_USERID` INT NOT NULL ,
`GROUP_GROUPID` INT NOT NULL ,
PRIMARY KEY (`USER_USERID`, `GROUP_GROUPID`) ,
INDEX `fk_USER_has_GROUP_GROUP1` (`GROUP_GROUPID` ASC) ,
INDEX `fk_USER_has_GROUP_USER` (`USER_USERID` ASC) ,
CONSTRAINT `fk_USER_has_GROUP_USER`
FOREIGN KEY (`USER_USERID` )
REFERENCES `jdbcrealm`.`TBLUSERS` (`USERID` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_USER_has_GROUP_GROUP1`
FOREIGN KEY (`GROUP_GROUPID` )
REFERENCES `jdbcrealm`.`TBLGROUPS` (`GROUPID` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
我在这里复制了一些有趣的、谷歌搜索的关于该主题的链接,这些链接对我有帮助。原来,我跟着第二个。也许其他人也会发现它们很有用。
http://docs.oracle.com/javaee/6/tutorial/doc/bnbxj.html http://blog.eisele.net/2011/01/jdbc-security-realm-and-form-based.html ...还有一些我不得不省略,因为第一篇文章中可能只包含两个链接。感谢您到目前为止的阅读。祝你好运,
塔马斯
第 2 部分 感谢您的回复。我创建了 2 个具有一对多关系的新表用户和组。在领域配置页面上,我为用户名、密码和组设置了表名和列。马特的评论也与链接一致(见下文我不能在这里发布)
[...] 这里有趣的部分是我使用的用户表和组表 v_user_role 作为属性的值。 v_user_role 是一个数据库 包含用户和组信息的视图。原因我 没有直接使用用户表是因为 glassfish 假设 用户表和组表都包含一个包含 用户名,这将导致重复数据。 [...]
-- -----------------------------------------------------
-- Table `jdbcrealm`.`user`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `jdbcrealm`.`user` ;
CREATE TABLE IF NOT EXISTS `jdbcrealm`.`user` (
`userid` VARCHAR(30) NOT NULL ,
`password` VARCHAR(45) NOT NULL ,
PRIMARY KEY (`userid`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `jdbcrealm`.`group`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `jdbcrealm`.`group` ;
CREATE TABLE IF NOT EXISTS `jdbcrealm`.`group` (
`groupid` VARCHAR(30) NOT NULL ,
`userid` VARCHAR(30) NOT NULL ,
INDEX `fk_group_user1` (`userid` ASC) ,
CONSTRAINT `fk_group_user1`
FOREIGN KEY (`userid` )
REFERENCES `jdbcrealm`.`user` (`userid` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
出现同样的错误。我还尝试将主键放在组表中的 groupid 列上,但从问题的角度来看,我没有遇到任何变化。有趣的是,我尝试对 1 个用户名、密码、组所在的表执行相同的操作,并且出现相同的错误。
走向解决方案和解决方案
Matt 的 cmets 帮了大忙,感谢这篇精彩的帖子。综上所述,在我写关于基于数据库的身份验证的问题时,很明显无法加载用户组。 server.log 中的错误消息表明了这一点。
但是,我的怀疑转向了表及其列名之间的链接。然而,在简化了用户组实体的数据模型之后,我无法解释为什么即使使用包含用户、密码和组的简单表也无法工作。我继续朝这个方向进行调查。我假设列名也会影响这一点。当我应用马特的配置时,“无法加载组”消息从 server.log 中消失了,但现象仍然存在。因此,我假设这些组可能已经加载,但也存在不同的问题。然后我采用了马特的配置并开始逐步更改列名以接近原始配置,但“无法加载组”消息没有出现在日志中。当我使用原始设置重现此案例并且日志消息不存在时,我知道日志记录有问题,它已经以某种方式被关闭了。于是我开始调查整个配置。
当我查看已部署的应用程序时,我选择了部署描述符并将它们加载到 glassfish 控制台上。 web.xml 没问题,它和我写的内容一样,但是 glassfish-web.xml 的内容完全不同!它的生成就像我没有 glassfish-web.xml 一样。然后我注意到我的 glassfish-web.xml 没有放在 WEB-INF 目录中。我将它移到那里并进行了“全部清理,构建”并部署了应用程序。之后我回到了 db 视图,它以多对多的关系表示 TBLUSERS 和 TBLGROUPS 之间的数据。我最喜欢这个解决方案,因为它从数据的角度显示了最清晰的画面。我在领域配置页面上设置了适当的列。我用两个用户“tamas”和“arpi”对其进行了测试。 “tamas”被添加到用户和管理员组,同时“arpi”被添加到用户组。角色和用户组之间的映射在 glassfish-web.xml 中。授予“tamas”对用户和管理员资源的访问权限,而“arpi”仅获得对用户资源的访问权限。
感谢您的帮助。塔马斯
【问题讨论】:
【参考方案1】:乍一看,我会发现您的表格列名。
根据我自己的经验,我记得用户表中的用户列需要与USER_GROUPS
表中的用户列具有完全相同的名称。匹配是通过列名完成的。
因此,您的 USER_GROUPS
表需要与 TBLUSERS
表中的用户名匹配的列 USERNAME
。
请注意,您必须为此更改表关系。
可能还有很多其他原因,但您可以尝试一下。
这是我的本地配置:
CREATE TABLE `user` (
`LOGIN` varchar(32) NOT NULL,
`password` varchar(256) DEFAULT NULL,
PRIMARY KEY (`LOGIN`)
)
CREATE TABLE `group` (
`IDGROUP` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`IDGROUP`)
)
CREATE TABLE `group_has_user` (
`IDGROUP` int(11) NOT NULL,
`LOGIN` varchar(32) NOT NULL,
PRIMARY KEY (`IDGROUP`,`LOGIN`),
KEY `fk_group_has_user_user1` (`LOGIN`),
CONSTRAINT `fk_group_has_user_user1` FOREIGN KEY (`LOGIN`)
REFERENCES `user` (`LOGIN`)
ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fk_group_has_user_group1` FOREIGN KEY (`IDGROUP`)
REFERENCES `group` (`IDGROUP`)
ON DELETE NO ACTION ON UPDATE NO ACTION
)
在 GF 管理控制台中进行以下设置:
这是我在 sun-web.xml(现在的 glassfish-web.xml)中的安全角色映射:
<security-role-mapping>
<role-name>user</role-name>
<group-name>1</group-name>
</security-role-mapping>
<security-role-mapping>
<role-name>sponsor</role-name>
<group-name>2</group-name>
</security-role-mapping>
<security-role-mapping>
<role-name>admin</role-name>
<group-name>3</group-name>
</security-role-mapping>
我在 web.xml 中直接在 login-config 下定义了以下安全角色:
<security-role>
<description/>
<role-name>user</role-name>
</security-role>
<security-role>
<description/>
<role-name>sponsor</role-name>
</security-role>
<security-role>
<description/>
<role-name>admin</role-name>
</security-role>
【讨论】:
嗨,马特,感谢您的回复。我将表关系更改为一对多,并将相同的用户名列添加到两个表中。不幸的是,它产生了同样的错误。其实我也用一张桌子试了一下…… 嗨,马特,感谢您的回复。我将表关系更改为一对多,并将相同的用户名列添加到两个表中。不幸的是,它产生了同样的错误。实际上,我也用一张桌子尝试过……我找到了一个很好的链接:jugojava.blogspot.com/2011/02/…,它也支持你的想法。我还按照此链接上的说明在原始表格上创建了一个视图,但卡在了同一个地方:无法加载组...再次非常感谢您的回复,Tamas 您能否在您的问题中更新您的表格配置?然后我可以将它与我自己的(工作)解决方案进行比较。 您可以使用问题下方的 edit 链接。它比评论更容易阅读。 谢谢。我将它作为“Part2”添加到原始问题中。我上面提到的链接:jugojava.blogspot.com/2011/02/…以上是关于Java EE 声明性安全性,无法为 JDBC 领域用户加载组的主要内容,如果未能解决你的问题,请参考以下文章
MySQLSyntaxErrorException:未知数据库 - JDBC - Java EE