Java EE declarative security, Cannot load group fo

2019-02-03 19:16发布

问题:

It is my first post here. I would have two questions with regard to declarative Java EE security: (1) file-based authentication and (2) DB-based authentication. I enclosed the relevant parts of the configuration for both questions. I run the code on Glassfish 3.1.1. Thank you for your assitance also in advance.

I was also looking for answers to my questions and found some useful examples which I put also at the bottom of the message. I tried to follow them so the present state of the configuration can contain details from these samples but they did not solve the problem.

-File-based authentication works all right if the "default principal to role mapping" is ticked otherwise it did not work even if a principal was added to the mapping. I might have configured something not in the right manner.

-DB-based authentication. It did not work as far as authorization is concerned because the group names could not be read. See details below. Authentication works all right i.e. the user is recognised. I have even tried with renaming the tables to avoid potential name collision with some internal stuff of Glassfish...

(1) File based authentication: File realm, 2 useres: user, admin added and assigned to the groups: user and admin (configurations/server-config/security/realms/file -> Manage Users)

configurations/server-config/security Default Principal To Role Mapping "ticked" -> it works Default Principal To Role Mapping "not ticked" -> it does not work even if the is added to the security mapping.

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>

Logged errors without the default principal mapping:

  1. No Principals mapped to Role [user].
  2. No Principals mapped to Role [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> 

Logged errors without the default principal mapping: 1. No Principals mapped to Role [user]. 2. No Principals mapped to Role [admin].


(2)DB-based authentication:

Realm changed the above realm to jdbcRealm in the web.xml

  • 1) m-n (many-to-many relationship between the users and groups table)

    SEC1111, Cannot load group for JDBC realm user [tamas].

  • 2) same for 1-n (one-to-many relationship between the users and groups table)

    SEC1111, Cannot load group for JDBC realm user [tamas].

  • 3) group name in the same table as user name and password

    SEC1111, Cannot load group for JDBC realm user [tamas].

Realm configuration: (I also tried to leave "Assign Groups" blank or to fill in "default" but the result was the same. )

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 

DB ER Diagram for the m-n relationship:

Image had to be omitted but as compensation :-) you find the SQL script below.

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;

I copy here some interesting, googled links on the topic which were helpful to me. Originally, I followed the second one. Maybe other people will also find them useful.

  • http://docs.oracle.com/javaee/6/tutorial/doc/bnbxj.html
  • http://blog.eisele.net/2011/01/jdbc-security-realm-and-form-based.html
  • ... and some more I had to omit as there may only be two links included in the first post.

Thank you for reading so far. Best wishes,

Tamas



Part 2 Thank you for the responses. I created 2 new tables user and group with one-to-many relationship. On the realm config page I set the table names and the columns for the username, pwd, and groups. Matt's comment is also in line with the link (see below I cannot post it here)

[...] Interesting part here is that for user table and group table I used v_user_role as the value for the property. v_user_role is a database view that contains both user and group information. The reason i didn't use the users table directly is because glassfish assumes that both the user table and the group table contain a column containing the user name and that would result in duplicate data. [...]

-- -----------------------------------------------------
-- 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;

The same error emerges. I attempted also in a way that I put a primary key on the column groupid in the group table but I experienced no change from point of view of the question. It is also interesting that I tried to do the same with 1 table in which usernames, pwds, groups are located and the same error comes.



Towards the Solution and the Solution

The comments from Matt helped a lot, thanks for this great posts. In summary, at the beginning when I wrote the question relating the DB-based authentication, it was clear that the user groups cannot be loaded. This was indicated by the error message in the server.log.

However, my suspicion turned towards the links between the tables and their column names. Nevertheless, after simplifying the data model for user-group entities, I could not explain why it did not work even with a simple table containing user, pwd and group. I continued the investigation in this direction. I assumed that also column names can influence this. When I applied Matt's configuration the "cannot load groups" message disappeared from the server.log but the phenomenon remained the same. Therefore I assumed that the groups could already be loaded but there was also a different problem. I took then Matt's config and started to change the column names back step-by-step to approach the original config but the "cannot load groups" message did not appear in the log. When I reproduced the case with my original settings and the log message was not there, I knew that something is wrong with the logging it had somehow been switched off. So I started investigating the whole configuration.

When I had a look to the deployed application, I selected the deployment descriptors and loaded them over the glassfish console. web.xml was all right it had the same content I wrote but glassfish-web.xml had a completely different content! It was generated as if I had had no glassfish-web.xml. Then I noticed that my glassfish-web.xml was not placed in the WEB-INF directory. I moved it there and made a "clean all, build" and deployed the application. Afterwards I came back to the db view which represents the data between TBLUSERS and TBLGROUPS in a many-to-many relationship. I like this solution the most as it shows the clearest picture from the point of view of the data. I set the appropriate columns on the realm config page. I tested it with two users "tamas" and "arpi". "tamas" was added to the user and admin groups meanwhile "arpi" was added to the user group. The mapping between the roles and the user groups is in the glassfish-web.xml. Access was given to "tamas" to both user and admin resources while "arpi" received access only to the user resources.

Thank you for the help. Tamas

回答1:

From the first glance I would spot on your table column names.

From my own experience I memorized that the user column in the user table needs to have exactly the same name as the user column in the USER_GROUPS table. The matching is done by column names.

So your USER_GROUPS table needs a column USERNAME that matches the user names from the TBLUSERS table.

Note that you have to change your table relations for this.

There can be a dozen of other reasons but you can give it a try.

This is my local configuration:

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
)

with the following settings in GF admin console:

Here is my security-role mapping from sun-web.xml (now 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>

And I have defined the following security-roles in web.xml directly below 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>