Skip to content

Tibor17/webapp-security

Repository files navigation

webapp-security

Typical JAAS in web applications.

1. Application server on real box

Download the application server

$ cd /opt
$ curl http://repo1.maven.org/maven2/org/wildfly/wildfly-dist/8.2.1.Final/wildfly-dist-8.2.1.Final.tar.gz --output wildfly-dist-8.2.1.Final.tar.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  113M  100  113M    0     0   607k      0  0:03:11  0:03:11 --:--:-- 1085k

and start the server with non-default configuration.

$ tar -xzf wildfly-dist-8.2.1.Final.tar.gz && rm -rf wildfly-dist-8.2.1.Final.tar.gz
$ export WILDFLY_HOME=/opt/wildfly-dist-8.2.1.Final
$ /opt/bin/standalone.bat -c standalone.xml -Djboss.server.config.dir=/opt/wildfly-dist-8.2.1.Final/customized-configs/1/
$ mkdir -p /opt/wildfly-dist-8.2.1.Final/customized-configs/1
$ cp -R /opt/wildfly-dist-8.2.1.Final/standalone/configuration/ /opt/wildfly-dist-8.2.1.Final/customized-configs/1/

Enable TRACE logs for the security subsystem.

<subsystem xmlns="urn:jboss:domain:logging:2.0">
	<console-handler name="CONSOLE">
-		<level name="INFO"/>
+		<level name="TRACE"/>
		<formatter>
			<named-formatter name="COLOR-PATTERN"/>
		</formatter>
	</console-handler>
	<periodic-rotating-file-handler name="FILE" autoflush="true">
		<formatter>
			<named-formatter name="PATTERN"/>
		</formatter>
		<file relative-to="jboss.server.log.dir" path="server.log"/>
		<suffix value=".yyyy-MM-dd"/>
		<append value="true"/>
	</periodic-rotating-file-handler>
	<logger category="com.arjuna">
		<level name="WARN"/>
	</logger>
	<logger category="org.apache.tomcat.util.modeler">
		<level name="WARN"/>
	</logger>
	<logger category="org.jboss.as.config">
		<level name="DEBUG"/>
	</logger>
	<logger category="sun.rmi">
		<level name="WARN"/>
	</logger>
	<logger category="jacorb">
		<level name="WARN"/>
	</logger>
	<logger category="jacorb.config">
		<level name="ERROR"/>
	</logger>
+   <logger category="org.jboss.security">
+       <level name="TRACE"/>
+    </logger>
	<root-logger>
		<level name="INFO"/>
		<handlers>
			<handler name="CONSOLE"/>
			<handler name="FILE"/>
		</handlers>
	</root-logger>
	<formatter name="PATTERN">
		<pattern-formatter pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
	</formatter>
	<formatter name="COLOR-PATTERN">
		<pattern-formatter pattern="%K{level}%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
	</formatter>
</subsystem>

Add PostgreSQL datasource and remove default H2 datasource.

<subsystem xmlns="urn:jboss:domain:datasources:2.0">
    <datasources>
-       <datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true">
-           <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
-           <driver>h2</driver>
-           <security>
-               <user-name>sa</user-name>
-               <password>sa</password>
-           </security>
-       </datasource>
+       <xa-datasource jndi-name="java:jboss/datasources/UserDS" pool-name="UserDS" enabled="true">
+                   <xa-datasource-property name="ServerName">
+               127.0.0.1
+           </xa-datasource-property>
+           <xa-datasource-property name="PortNumber">
+               5432
+           </xa-datasource-property>
+           <xa-datasource-property name="DatabaseName">
+               jaaswf8
+           </xa-datasource-property>
+           <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
+           <driver>postgres</driver>
+           <xa-pool>
+               <min-pool-size>1</min-pool-size>
+               <max-pool-size>20</max-pool-size>
+           </xa-pool>
+           <security>
+               <user-name>postgres</user-name>
+               <password>postgres</password>
+           </security>
+           <validation>
+               <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker"/>
+               <check-valid-connection-sql>select 1</check-valid-connection-sql>
+               <validate-on-match>false</validate-on-match>
+               <background-validation>true</background-validation>
+               <background-validation-millis>25000</background-validation-millis>
+               <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter"/>
+           </validation>
+           <timeout>
+               <idle-timeout-minutes>1</idle-timeout-minutes>
+           </timeout>
+       </xa-datasource>
        <drivers>
-           <driver name="h2" module="com.h2database.h2">
-               <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
-           </driver>
+           <driver name="postgres" module="org.postgres">
+               <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
+           </driver>
        </drivers>
    </datasources>
</subsystem>

Remove default datasource of H2 from default bindings.

- <default-bindings context-service="java:jboss/ee/concurrency/context/default" datasource="java:jboss/datasources/ExampleDS" jms-connection-factory="java:jboss/DefaultJMSConnectionFactory" managed-executor-service="java:jboss/ee/concurrency/executor/default" managed-scheduled-executor-service="java:jboss/ee/concurrency/scheduler/default" managed-thread-factory="java:jboss/ee/concurrency/factory/default"/>
+ <default-bindings context-service="java:jboss/ee/concurrency/context/default" managed-executor-service="java:jboss/ee/concurrency/executor/default" managed-scheduled-executor-service="java:jboss/ee/concurrency/scheduler/default" managed-thread-factory="java:jboss/ee/concurrency/factory/default"/>

Add the SQL driver for the PostgresSQL database

Example 1. $WILDFLY_HOME/modules/org/postgres/main/module.xml
<?xml version="1.0" ?>

<module xmlns="urn:jboss:module:1.1" name="org.postgres">

    <resources>
        <resource-root path="postgresql-42.2.8.jar"/>
    </resources>

    <dependencies>
        <module name="javax.api"/>
        <module name="javax.transaction.api"/>
    </dependencies>
</module>

and add the driver to the directory $WILDFLY_HOME/modules/org/postgres/main/.

Install PostgreSQL database, create the database jaaswf8

-- Database: jaaswf8

-- DROP DATABASE jaaswf8;

CREATE DATABASE jaaswf8
    WITH
    OWNER = postgres
    ENCODING = 'UTF8'
    LC_COLLATE = 'English_United States.1250'
    LC_CTYPE = 'English_United States.1250'
    TABLESPACE = pg_default
    CONNECTION LIMIT = -1;

and create the tables for JAAS

CREATE TABLE public.userroles
(
    username character varying(255) COLLATE pg_catalog."default",
    role character varying(32) COLLATE pg_catalog."default"
)
WITH (
    OIDS = FALSE
)
TABLESPACE pg_default;

ALTER TABLE public.userroles
    OWNER to postgres;

CREATE TABLE public.users
(
    username character varying(255) COLLATE pg_catalog."default" NOT NULL,
    passwd character varying(255) COLLATE pg_catalog."default",
    CONSTRAINT users_pkey PRIMARY KEY (username)
)
WITH (
    OIDS = FALSE
)
TABLESPACE pg_default;

ALTER TABLE public.users
    OWNER to postgres;

Now run the server

$ $WILDFLY_HOME/bin/standalone.sh -c standalone.xml -Djboss.server.config.dir=/opt/wildfly-dist-8.2.1.Final/customized-configs/1/

This is the same configuration of Wildfly runtime in IntelliJ IDEA:

wildfly 8.2.1 intellij idea Run Debug Configurations

2. Build docker image and run with external PostgreSQL database

2.1. Initial setup of PostgreSQL database

If you use a fresh installation of PostgreSQL on a real box, the web application will run properly but the Docker container will not. You will see the following error:

PSQLException: FATAL: no pg_hba.conf entry for host "172.22.192.1", user "postgres", database "jaaswf8", SSL off
sslmode=disable

Caused by: org.postgresql.util.PSQLException: FATAL: no pg_hba.conf entry for host "172.22.192.1", user "postgres", database "jaaswf8", SSL off

Fix the config files of PostgreSQL database and allow Docker host IP address to access the database. Beforehand you should check the IP address using the command ipconfig /all on Windows or ifconfig -a on Linux. Then you can see a nat ip address of Docker NAT IP address copy it.

Example 2. Docker NAT IP (172.22.192.1)
Ethernet adapter vEthernet (nat):

   Connection-specific DNS Suffix  . :
   Description . . . . . . . . . . . : Hyper-V Virtual Ethernet Adapter #3
   Physical Address. . . . . . . . . : 00-15-5D-9C-CC-96
   DHCP Enabled. . . . . . . . . . . : No
   Autoconfiguration Enabled . . . . : Yes
   Link-local IPv6 Address . . . . . : fe80::90f1:6619:be88:2d24%53(Preferred)
   IPv4 Address. . . . . . . . . . . : 172.22.192.1(Preferred)
   Subnet Mask . . . . . . . . . . . : 255.255.240.0
   Default Gateway . . . . . . . . . :
   DHCPv6 IAID . . . . . . . . . . . : 889197917
   DHCPv6 Client DUID. . . . . . . . : 00-01-00-01-23-C7-48-B0-34-E6-D7-38-4B-9B
   DNS Servers . . . . . . . . . . . : fec0:0:0:ffff::1%1
                                       fec0:0:0:ffff::2%1
                                       fec0:0:0:ffff::3%1
   NetBIOS over Tcpip. . . . . . . . : Enabled

2.1.1. Configuring network access to the database in pg_hba.conf

Example 3. $POSTGRE_HOME/data/pg_hba.conf
# TYPE  DATABASE        USER            ADDRESS                 METHOD

# IPv4 local connections:
host    all             all             127.0.0.1/32            md5
# IPv6 local connections:
host    all             all             ::1/128                 md5
# Allow replication connections from localhost, by a user with the
# replication privilege.
#host    replication    all             127.0.0.1/32            md5
#host    replication    all             ::1/128                 md5
host    all             all             ::1/128                 md5
host    all             all             172.22.192.1/32         md5

2.1.2. Configuring network access to the database in postgresql.conf

Make sure that the configuration file postgresql.conf accepts all addresses * specified in ADDRESS see pg_hba.conf. Configuring the addresses twice does not make sense.

The number of connections is important for connection pool(s) in datasources of the server and the JTA transactions (XA datasources). See the script add-jboss-xadatasource.cli and max-pool-size="20". Five more connections are reserved for e.g. the use of pgAdmin tool.

Example 4. $POSTGRE_HOME/data/postgresql.conf
listen_addresses = '*'
max_connections = 25

2.2. Execution of web application in Docker

Example 5. Build the image 'tibor17/webapp-jaas-wildfly8:latest'.
$ docker build -t tibor17/webapp-jaas-wildfly8:latest .
Example 6. Run the docker container
$ docker run -it --rm -p 8080:8080 -p 9990:9990 -p 5432:5432 --add-host=database:172.22.192.1 -e POSTGRESQL_HOST=database -e LOG_LEVEL=INFO tibor17/webapp-jaas-wildfly8:latest

Now open a new commandline and check the hash id of currently running docker container. Then stop the container.

Example 7. $ docker ps
CONTAINER ID        IMAGE                                 COMMAND                  CREATED             STATUS              PORTS                                                                    NAMES
7bbf8105cb73        tibor17/webapp-jaas-wildfly8:latest   "./docker-entrypoint…"   9 minutes ago       Up 9 minutes        0.0.0.0:5432->5432/tcp, 0.0.0.0:8080->8080/tcp, 0.0.0.0:9990->9990/tcp   gifted_rhodes

Stop the application when necessary:

$ docker stop -t 1 7bbf8105cb73

Now you can use browser and use the URL http://localhost:8080/wf8/.

You can run the named container wf8app in detached mode. The container is removed after stopped.

$ docker run --name=wf8app -d --stop-timeout 3 --rm -p 8080:8080 -p 9990:9990 -p 5432:5432 --add-host=database:172.22.192.1 -e POSTGRESQL_HOST=database -e LOG_LEVEL=INFO tibor17/webapp-jaas-wildfly8:latest

Now list the containers and their status.

Example 8. $ docker ps
CONTAINER ID        IMAGE                                 COMMAND                  CREATED             STATUS                    PORTS                                                                    NAMES
2f6c08722d8e        tibor17/webapp-jaas-wildfly8:latest   "./docker-entrypoint…"   22 seconds ago      Up 21 seconds (healthy)   0.0.0.0:5432->5432/tcp, 0.0.0.0:8080->8080/tcp, 0.0.0.0:9990->9990/tcp   wf8app

Suppose the application is unhealthy.

CONTAINER ID        IMAGE                                 COMMAND                  CREATED             STATUS                      PORTS                                                                    NAMES
18cdc720748a        tibor17/webapp-jaas-wildfly8:latest   "./docker-entrypoint…"   29 seconds ago      Up 27 seconds (unhealthy)   0.0.0.0:5432->5432/tcp, 0.0.0.0:8080->8080/tcp, 0.0.0.0:9990->9990/tcp   wf8app

The status JSON can be utilized by Kubernetes. Type the command:

Example 9. $ docker inspect --format="{{json .State.Health}}" wf8app
{
"Status": "unhealthy",
"FailingStreak": 12,
"Log": [
    {
    "Start": "2019-10-03T23:35:00.8760843Z",
    "End": "2019-10-03T23:35:01.0080689Z",
    "ExitCode": 1,
    "Output": ""
    },
    {
    "Start": "2019-10-03T23:35:03.039699Z",
    "End": "2019-10-03T23:35:03.1908468Z",
    "ExitCode": 1,
    "Output": ""
    },
    {
    "Start": "2019-10-03T23:35:05.2196635Z",
    "End": "2019-10-03T23:35:05.3563012Z",
    "ExitCode": 1,
    "Output": ""
    },
    {
    "Start": "2019-10-03T23:35:07.3732945Z",
    "End": "2019-10-03T23:35:07.515681Z",
    "ExitCode": 1,
    "Output": ""
    },
    {
    "Start": "2019-10-03T23:35:09.5392128Z",
    "End": "2019-10-03T23:35:09.6791588Z",
    "ExitCode": 1,
    "Output": ""
    }
  ]
}

On Linux: docker inspect --format='{{json .State.Health}}' wf8app

Check the network settings of the container. The IP address of container is 172.17.0.2 on my box.

Example 10. $ docker inspect --format="{{json .NetworkSettings.Networks}}" wf8app
{
    "bridge": {
        "IPAMConfig": null,
        "Links": null,
        "Aliases": null,
        "NetworkID": "978863f6fae211f5e9f180c3366201650b3beaebc2821060c38dd46a170e4bdc",
        "EndpointID": "9fe332d0a92c9d15233ced7225e7b0e6e883c9c5d281c864253517d9e4c11d1e",
        "Gateway": "172.17.0.1",
        "IPAddress": "172.17.0.2",
        "IPPrefixLen": 16,
        "IPv6Gateway": "",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "MacAddress": "02:42:ac:11:00:02",
        "DriverOpts": null
    }
}

The container can be stopped by its ID or the name of the container docker stop -t 1 wf8app

3. References

Problem with the latest docker-compose on Windows and workaround with version 1.19
Kubernetes on Docker
PostgreSQL network config in Docker
RUN echo "host all  all    0.0.0.0/0  md5" >> /var/lib/postgresql/pg_hba.conf
RUN echo "listen_addresses='*'" >> /var/lib/postgresql/postgresql.conf
PostgreSQL and JavaEE in Docker
Using embed-server in jboss-cli.sh command
Datasources configuration for all databases in Wildfly
Docker Compose Tutorial
Realistic docker-compose.yml for PostgreSQL and WildFly
Securing JavaEE REST API with Keycloak
How to add JMS to the pure standalone.xml and entire AMQ configuration and queues
PostgreSQL Docker container is not exposed properly (works only on version 10)
Elytron Referenes
Sebastian Daschner
JIB (related to Romain’s blog above)