- Filtering clients by source IP addresses
- Requiring authentication and authorization
- Data transport integrity and confidentiality (SSL)
We will explore each one of these in turn
- Limit access to web applications by client IP or hostname
Configured through Tomcat Valves
Different levels:
<Engine>
(global),<Host>
(per virtual host),<Context>
(per web application)<Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="192.168.*,127.*" />
<Valve className="org.apache.catalina.valves.RemoteHostValve" deny="spamhost.com" />
Configured through a Servlet Filter
- Simple implementation is provided by JBoss but servlet filters are Java EE AS-independent
-
To limit client access through Tomcat, add a desired
<Valve>
in<Engine>
or<Host>
elements within${jboss.server.home.url}/deploy/jbossweb.sar/server.xml
file Limiting per web application can be still done through Tomcat by creating a
<Context>
file${jboss.server.home.url}/deploy/<app>.war/WEB-INF/context.xml
:<Context> <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="192.168.*.*" /> </Context>
To limit client access in a application-server-neutral way, configure a servlet filter in
WEB-INF/web.xml
file as follows:<web-app ...> ... <filter> <filter-name>RemoteHostFilter</filter-name> <filter-class>org.jboss.remotehostfilter.RemoteHostFilter</filter-class> <init-param> <param-name>allow</param-name> <param-value>192.168.*,127.*</param-value> </init-param> </filter> <filter-mapping> <filter-name>RemoteHostFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ... </web-app>
A simple implementation of this filter can be found at http://community.jboss.org/wiki/LimitAccessToCertainClients
Security is a fundamental part of any enterprise application. You need to be able to restrict who is allowed to access your applications and control what operations application users may perform.
- JAAS - Java Authentication and Authorization Service (pure Java)
- Pluggable Authentication Module framework: JNDI, UNIX, Windows, Kerberos, Keystore
- Support for single sing-on
- Role-based access control
- Separates business logic from A&A
Declarative (XML-based)
- Described in deployment descriptors instead of being hard-coded
- Isolate security from business-level code
For example, consider a bank account application. The security requirements, roles, and permissions will vary depending on how is the bank account accessed:
- via the internet (username + password), via an ATM (card + pin), or at a branch (Photo ID + signature).
- We benefit by separating the business logic of how bank accounts behave from how bank accounts are accessed.
Securing a Java EE application is based on the specification of the application security requirements via the standard Java EE deployment descriptors.
-
EJBs and web components in an enterprise application by using the
ejb-jar.xml
andweb.xml
deployment descriptors.
-
EJBs and web components in an enterprise application by using the
Adding security-constraint in web.xml:
<web-app ...> ... <security-constraint> <web-resource-collection> <web-resource-name>All Resources</web-resource-name> <description>Protect all content</description> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>MyRole</role-name> </auth-constraint> </security-constraint> ... </web-app>
-
Element
<security-constraint>
declares the web resources to be protected and the role required to access those resources. -
Element
<web-resource-name>
is required, and it simply assigns a name to the declared<web-resource-collection>
. -
Element
<description>
is optional, and it provides textual description of the declared<web-resource-collection>
. Element
<url-pattern>
is optional (although, without it the<web-resource-collection>
is ignored), and it declares to which URL patterns this security constraint applies. URL patterns can be catch-all ("/*") or they can be repeated to list specific resources. For example:<url-pattern>/MySecureHandler</url-pattern> <url-pattern>/MySecureArea/*</url-pattern> <url-pattern>*.jsp</url-pattern>
- The preceding slash (/) character makes the URLs absolute within the web application only.
In addition to URL patterns, it is also possible to limit the security constraint to HTTP methods using the
<http-method>
element as follows:<web-resource-collection> ... <http-method>POST</http-method> <http-method>GET</http-method> </web-resource-collection>
-
If the
<http-method>
element is omitted, the default behavior is to apply the security constraint to all HTTP methods. -
The
<auth-constraint>
element indicates the user roles that should be permitted access to this resource collection. The<role-name>
used here must either correspond to the<role-name>
of one of the<security-role>
elements defined for this web application (more on this soon), or be the specially reserved role-name "*" that is a compact syntax for indicating all roles in the web application. If no roles are defined, no user is allowed access to the portion of the web application described by the containing security-constraint. JBoss AS matches role names case sensitively when determining access. Adding login configuration:
<web-app ...> ... <security-constraint> ... </security-constraint> <login-config> <auth-method>BASIC</auth-method> <realm-name>My Secure Application</realm-name> </login-config> ... </web-app>
Element <login-config>
configures the login method for the secured resource.
In this case we just use HTTP BASIC authentication, but other options for JBoss are: DIGEST
, FORM
, and CLIENT-CERT
. We will cover some of these later.
Declaring security roles:
<web-app ...> ... <security-constraint> ... <auth-constraint> <role-name>MyRole</role-name> </auth-constraint> </security-constraint> <login-config> ... </login-config> <security-role> <description>All members of MyRole</description> <role-name>MyRole</role-name> </security-role> ... </web-app>
If multiple roles are desired, declare them as follows:
<web-app ...> ... <security-constraint> <web-resource-collection> ... </web-resource-collection> <auth-constraint> <role-name>Manager</role-name> </auth-constraint> <auth-constraint> <role-name>Administrator</role-name> </auth-constraint> </security-constraint> <login-config> ... </login-config> <security-role> <role-name>Manager</role-name> </security-role> <security-role> <role-name>Administrator</role-name> </security-role> ... </web-app>
- Already enabled by default
WEB-INF/classes/users.properties
:john=secret bob=abc123 mike=passwd
WEB-INF/classes/roles.properties
:john=MyRole bob=MyRole,Manager mike=Manager,Administrator
Provided by
org.jboss.security.auth.spi.UsersRolesLoginModule
configured in file${jboss.server.config.url}/login-config.xml
:<policy> ... <application-policy name="other"> <authentication> <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required" /> </authentication> </application-policy> ... </policy>
![]() | Note |
---|---|
The properties files |
To change the names of these files, expand the
<login-module>
as follows:<login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required"> <module-option name="usersProperties">myUsers.properties</module-option> <module-option name="rolesProperties">myRoles.properties</module-option> </login-module>
- Fetches login info from a RDBMS
- Works with existing DB schemas
- Uses pooled database connections
- Scales well as the user population grows
- Does not require server or application restarts on info change
Database Login Module depends on our ability to set up (and link to) a JBoss-managed DataSource (database connection pool).
term#> mysql/bin/mysql -u root -p mysql> CREATE DATABASE Authority; mysql> USE Authority; mysql> CREATE TABLE Users (Username VARCHAR(32) NOT NULL PRIMARY KEY,Password VARCHAR(32) NOT NULL); mysql> CREATE TABLE Roles (Username VARCHAR(32) NOT NULL,Rolename VARCHAR(32) NOT NULL,PRIMARY KEY (Username, Rolename)); mysql> GRANT SELECT ON Authority.* TO authority@localhost IDENTIFIED BY "authsecret";
It is important that the password field be at least 32 characters in order to accommodate MD5-digest-based passwords (more on this later).
You do not have to create a separate database, nor do you need separate tables, but we assume that we are starting from scratch. The default JBoss AS schema for User/Role information is as follows:
- Table Principals(PrincipalID text, Password text)
- Table Roles(PrincipalID text, Role text, RoleGroup text)
You also do not need a auth-specific read-only database user, but we create one because it is a good practice.
Populate the database. For example:
INSERT INTO Users VALUES ("john", "secret"); INSERT INTO Roles VALUES ("john", "MyRole"); INSERT INTO Users VALUES ("bob", "abc123"); INSERT INTO Roles VALUES ("bob", "MyRole"); INSERT INTO Roles VALUES ("bob", "Manager"); INSERT INTO Users VALUES ("mike", "passwd"); INSERT INTO Roles VALUES ("mike", "Manager"); INSERT INTO Roles VALUES ("mike", "Admin");
Create
deploy/authority-ds.xml
:<datasources> <local-tx-datasource> <jndi-name>AuthorityDB</jndi-name> <connection-url> jdbc:mysql://localhost:3306/Authority? autoReconnect=true </connection-url> <driver-class>com.mysql.jdbc.Driver</driver-class> <user-name>authority</user-name> <password>authsecret</password> ... </local-tx-datasource> </datasources>
Define a database connection pool (resource) that will provide connectivity to the Authority database.
Add to
conf/login-config.xml
:<application-policy name="MyPolicy"> <authentication> <login-module flag="required" code="org.jboss.security.auth.spi.DatabaseServerLoginModule"> <module-option name="dsJndiName">java:/AuthorityDB</module-option> <module-option name="principalsQuery">SELECT Password FROM Users WHERE Username=?</module-option> <module-option name="rolesQuery">SELECT Rolename, "Roles" FROM Roles WHERE Username=?</module-option> </login-module> </authentication> </application-policy>
- Application policy name declares a new policy. We will reference this name in each [web] application that wishes to use it.
The
required
flag means that the login module is required to succeed.- If it succeeds or fails, authentication still continues to proceed down the LoginModule list
-
Other options are:
requisite
,sufficient
, andoptional
Module option
dsJndiName
:- Defines the JNDI name of the RDBMS DataSource that defines logical users and roles tables
-
Defaults to
java:/DefaultDS
Module option
principalsQuery
:- Defines a prepared SQL statement that queries the password of a given username
-
Defaults to
select Password from Principals where PrincipalID=?
Module option
rolesQuery
:- Defines a prepared SQL statement that queries role names (and groups) of a given username
-
The default group name is
Roles
(hard-coded). Defaults toselect Role, RoleGroup from Roles where PrincipalID=?
Add to
WEB-INF/jboss-web.xml
:<jboss-web> <security-domain>java:/jaas/MyPolicy</security-domain> </jboss-web>
-
Default security domain is
other
, which authenticates against the properties files -
Security domains declared in
conf/login-config.xml
are relative tojava:/jaas/
JNDI context
Configure hashed passwords in
conf/login-config.xml
:<login-module ...> ... <module-option name="hashAlgorithm">MD5</module-option> <module-option name="hashEncoding">hex</module-option> </login-module>
Change users.properties:
john=5ebe2294ecd0e0f08eab7690d2a6ee69 bob=e99a18c428cb38d5f260853678922e03 mike=76a2173be6393254e72ffa4d6df1030a
Session-based
-
Allows Logout -
session.invalidate()
- Automatically expires when the session expires
- More efficient and secure - single authentication
-
Allows Logout -
Fully customizable
- Control the layout of the login page
- Control the layout of the error page
- Provide links to "user registration" or "recover password" actions
- Support for FORM-based login is part of the Java EE specification, and like the rest of JAAS-based security, it is independent of the application server
With the FORM-based login, the server forces the users to login via an HTML form when it detects the user’s session is not authenticated
- This is accomplished by forwarding the users' requests to the login page
- In case of authentication failures, users are sent to the login error page
JBoss handler:
j_security_check
for paramsj_username
andj_password
<html> <head><title>Login Form</title></head> <body> <h1>Login Form</h1> <form action="j_security_check" method="post"> Username: <input type="text" name="j_username"/><br/> Password: <input type="password" name="j_password"/><br/> <input type="submit" value="Login" /> </form> </body> </html>
To support non-cookie-based-session-tracking, change
j_security_check
to<%= response.encodeURL("j_security_check") %>
which will add
JSESSIONID
to the request URL if needed.
Displays the error message if the authentication fails
<html> <head><title>Login Error</title></head> <body> <h1>Authentication Error</h1> <p style="color: red"> Invalid username and/or password. </p> <p><a href="Login.jsp">Try again?</a></p> </body> </html>
This page is only shown if user enters invalid username and/or password. Authorization errors (user not in required role) are handled separately.
Update
<login-config>
inweb.xml
:<login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/Login.jsp</form-login-page> <form-error-page>/LoginError.jsp</form-error-page> </form-login-config> </login-config>
-
Create (or import) SSL certificates using
keytool
Java command-line utility - Configure SSL connector in Tomcat
-
Require SSL per application/context using
<user-data-constraint>
![]() | Note |
---|---|
Adding support for SSL (Secure Socket Layer) is only useful if JBoss AS acts as a stand-alone web server. If JBoss AS is fronted by another web server, like Apache HTTPD, then the security of the communication channel becomes the responsibility of that web server. In that case, JBoss AS communicates with the web server over an unsecured channel (plain-text), but the web server still informs JBoss about the security protocol it has negotiated with the end client. |
- Only JKS or PKCS12 formats are supported
-
Use JDK’s
keytool
command-line tool - Keystore password and certificate password have to be the same (default is "changeit")
- Certificate alias is "tomcat"
- Use RSA algorithm for broader support
- Use JBoss-specific keystore file
- Use site hostname for cert’s common name
For example, run the following from within ${jboss.server.home.url}
directory:
keytool -genkey -keystore conf/ssl.ks -storepass secret -alias tomcat -keyalg RSA -keypass secret What is your first and last name? [Unknown]: localhost What is the name of your organizational unit? [Unknown]: IT What is the name of your organization? [Unknown]: Secure Org What is the name of your City or Locality? [Unknown]: San Francisco What is the name of your State or Province? [Unknown]: CA What is the two-letter country code for this unit? [Unknown]: US Is CN=localhost, OU=IT, O=Secure Org, L=San Francisco, ST=CA, C=US correct? [no]: yes
Refer to http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html for more info.
Add (uncomment) in
${jboss.server.home.dir}/deploy/jbossweb.sar/server.xml
file:<Connector protocol="HTTP/1.1" SSLEnabled="true" port="8443" address="${jboss.bind.address}" scheme="https" secure="true" clientAuth="false" keystoreFile="${jboss.server.home.dir}/conf/chap8.keystore" keystorePass="rmi+ssl" sslProtocol = "TLS" />
If you change the port to 443 (or any other port number), make sure that you also set redirectPort="443"
in both the non-SSL HTTP and AJP connector elements.
See http://tomcat.apache.org/tomcat-6.0-doc/config/http.html for additional <Connector>
options.
When starting up JBoss AS, the console should print the following lines:
... 14:41:01,002 INFO [Http11Protocol] Initializing Coyote HTTP/1.1 on http-0.0.0.0-8080 14:41:02,195 INFO [Http11Protocol] Initializing Coyote HTTP/1.1 on http-0.0.0.0-8443 ...
When you point your browser to http://localhost:8443/status you will get a browser warning telling you that the SSL certificate has not been signed by a certification authority that you trust. This is expected, since we signed our own certificate. Skipping the warning should show the SSL-protected page (pad-lock).
Add within a
<security-constraint>
element (inWEB-INF/web.xml
file):<user-data-constraint> <description>Require SSL</description> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint>
-
Upon making a request over a non-SSL connection, the browser is automatically redirected to the
redirectPort
as defined in the<Connector>
element
![]() | Note |
---|---|
The element |
Filter out clients coming from remote interfaces on
- One of the virtual hosts
- One of the deployed applications
Protect an application with A&A
- Plain text
- Database
- Secure Passwords
Add support for SSL
- Require SSL in one or more of the applications
To filter clients by their source IP see Section 16.2, “Filtering Clients by Source”
-
For a virtual host, add
<Valve>
to<Host>
in Tomcat’sserver.xml
-
For a web application, add
<Valve>
to<Context>
in application’sWEB-INF/context.xml
file
To implement authentication and authorization (Section 16.3, “Authentication & Authorization”):
- Plain text (Section 16.5, “Plain-Text Login Module”)
- Database (Section 16.6, “Database Login Module”)
- Securing passwords (Section 16.6.5, “Securing Passwords”)
To add support for SSL (Section 16.8, “Configuring JBoss AS for SSL”):
- Require SSL (Section 16.12, “Requiring SSL in Apps”)
- By default in JBoss, every message sent can be accessed by all consumers connected to the destination.
- To restrict this, we must plug JBM users into JBossSX.
![]() | Note |
---|---|
|
First, declare a new security domain in the conf/login-config.xml
file in your server configuration set folder:
<policy> ... <application-policy name="JMSRealm"> <authentication> <login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required"> <module-option name="dsJndiName">java:/MySqlDS</module-option> <module-option name="principalsQuery"> SELECT passwd FROM jbm_user WHERE user_id=? </module-option> <module-option name="rolesQuery"> SELECT role_id, 'Roles' FROM jbm_role WHERE user_id=? </module-option> </login-module> </authentication> </application-policy> ... </policy>
Then, add the security domain you just created to the configuration of JBM security store that you can find in the deploy/messaging/messaging-jboss-beans.xml
:
<bean name="SecurityStore" class="org.jboss.jms.server.jbosssx.JBossASSecurityMetadataStore"> ... <property name="securityDomain">JMSRealm</property> <!----> ... </bean>
Create now a secured Topic:
<mbean code="org.jboss.jms.server.destination.TopicService" name="jboss.messaging.destination:service=Topic,name=securedTopic" xmbean-dd="xmdesc/Topic-xmbean.xml"> <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends> <depends>jboss.messaging:service=PostOffice</depends> <!----> <attribute name="SecurityConfig"> <security> <role name="publisher" read="true" write="true"/> </security> </attribute> </mbean>
This is where you say that you want your consumers to have the publisher role.
The read property allows the consumer to read messages from the destination.
The write property allows the consumer to send messages to the destination.
|
![]() | Note |
---|---|
The |
Finally, If a developer want to use the secured connection for this Topic:
connection = cf.createConnection("dynsub","dynsub");
- Running JBoss AS with low privileges
- File system security
Securing console applications/tools
- Restricting remote shutdown
- Protecting twiddle tool
- Securing other JBoss AS services
- Running with Java Security Manager
- Running behind a firewall
We will examine each of these in turn.
Do not run JBoss AS as root / Administrator
- Deployed applications and services run with the same privileges as the JBoss AS itself
- Create a low-privileged JBoss system user
JBoss, being a Java app, cannot switch its effective user id after starting
- Running without root privileges forces you to use ports >=1024 (default) on a Unix/Linux system
- Front JBoss AS with a web server (like Apache HTTPD) or setup firewall-based port forwarding for access over default HTTP(S) ports: 80, 443
Creating low-privileged users for system services is a common practice on Unix/Linux environments. On Windows, JBoss AS would typically be configured to run with a default System account. Also, Windows does not have a concept of privileged ports like Unix/Linux systems.
-
JBoss user must have at least read access to all files and directories under
${jboss.home_url}
-
JBoss user must have write access to
data/
,log/
,tmp/
, andwork/
directories under${jboss.server.home.url}
(underdefault
configuration set) -
Depending on the deployed apps' requirements, JBoss user may need write access to parts of
${jboss.server.home.url}/deploy
dir
Other users should in particular have no access to ${jboss.server.config.url}
and
${jboss.server.home.url}/deploy
directories as these often contain sensitive information like database or SSL-certificate passwords.
Although supported by NTFS, file system security is often not employed to secure system services like JBoss AS under Windows.
- Used by the twiddle tool and the remote shutdown - by default unsecured
Simples solution is to remove it
-
No remote shutdown (send
TERM
signal) - No programmatic remote management
-
No remote shutdown (send
Secure it by adding an authentication interceptor to the Invoker MBean
- Just needs to be uncommented
In deploy/jmx-invoker-adaptor-server.sar/META-INF/jboss-service.xml
(JBoss 3.2.x) or
deploy/jmx-invoker-service.xml
(JBoss 4.x and JBoss 5.x) under ${jboss.server.home.url}
, uncomment the following:
<!-- Uncomment to require authenticated users <descriptors> <interceptors> <interceptor code="org.jboss.jmx.connector.invoker.AuthenticationInterceptor" securityDomain="java:/jaas/jmx-console"/> </interceptors> </descriptors> -->
By default, the security domain java:/jaas/jmx-console
authenticates against file
default/conf/props/jmx-console-users.properties
This file is in <user>=<password> format. Roles are not important.
To specify the username and password for twiddle or shutdown scripts, use -u <user> -p <password>
command-line switches.
Both
jmx-console
andweb-console
are standard web applications- Remove if not needed?
- Filter by IP
- Use declarative security to require A&A
- Require SSL
- Declarative security already present, just needs to be uncommented
Requiring authentication and authorization for jmx-console
:
-
Uncomment
<security-constraint>
inweb.xml
and<security-domain>
injboss-web.xml
under${jboss.server.home.url}/deploy/jmx-console.war/WEB-INF/
-
Set or change the admin password in
${jboss.server.config.url}/props/jmx-console-users.properties
Requiring authentication and authorization for web-console:
Uncomment
<security-constraint>
inweb.xml
and<security-domain>
injboss-web.xml
under-
${jboss.server.home.url}/deploy/management/web-console.war/WEB-INF
(JBoss version<4.0.2) OR -
${jboss.server.home.url}/deploy/management/console-mgr.sar/web-console.war/WEB-INF/
(JBoss version>=4.0.2)
-
-
Update
${jboss.server.config.url}/login-config.xml
such that<application-policy name="web-console">
loadsusersProperties
fromprops/web-console-users.properties
androlesProperties
fromprops/web-console-roles.properties
- Add a user that belong to JBossAdmin role in the two properties files
Restart JBoss for the changes to take effect.
Remove it
-
Undeploy
${jboss.server.home.url}/deploy/hsqldb-ds.xml
-
Provide
DefaultDS
for services that depend on it (like JMS MQ)
-
Undeploy
Keep it but disable remote access to it
-
Disable
jboss:service=Hypersonic
Mbean inhsqldb-ds.xml
-
Disable
To disable remote access to Hypersonic DB:
-
Edit
${jboss.server.home.url}/deploy/hsqldb-ds.xml
-
Comment out
<mbean name="jboss:service=Hypersonic">
-
Change
<connection-url>
in<local-tx-datasource>
from localhost:1701 to a local resource likejdbc:hsqldb:${jboss.server.data.dir}/hypersonic/localDB
-
Comment out the
<depends>
element in<local-tx-datasource>
referring tojboss:service=Hypersonic
- Run JBoss AS in a secure sand box controlled by a security policy (file)
- Control access to resources such as JVM, system settings, file system, and network communication (inbound and outbound)
- Secure as long as all code is pure Java
- Disabled by default
- Hard to configure
- Slight runtime overhead
To enable, edit $JBOSS_HOME/bin/run.conf
and add to JAVA_OPTS
:
* -Djava.security.manager
and
* -Djava.security.policy=<policy-file>
Enabling the security manager is easy. The hard part is to come up with a suitable security policy.
To enable all permissions, start with security.policy
:
grant { permission java.security.AllPermission; };
To figure out which permissions you need, you can debug the security manager.
Run java -Djava.security.debug=help
to see a list of debugging options. Using -Djava.security.debug=all
in JAVA_OPTS
is the most verbose (probably too verbose), whereas setting java.security.debug
to access,failure may be sufficient to determine a suitable security policy.
Decide which services need to be visible from the outside world
- HTTP, HTTPS (unless running behind a web server such as Apache HTTPD)
- Naming Service: RMI, Registry?
- SNMP?
- JRMP Invoker?
Protect all other services
- JMS MQ
- HA and clustering services in all configuration
Listening ports in default configuration:
- 1098 TCP NamingService RMI
- 1099 TCP Naming Service Registry
- 4444 TCP JRMP Invoker RMI
- 4445 TCP Pooled Invoker Server
- 8009 TCP Tomcat AJP
- 8080 TCP Tomcat HTTP
- 8083 TCP Web Service
- 8093 TCP JMS MQ UIL Server
Additional listening ports in all configuration:
- 1100 TCP HA Naming Service
- 1101 TCP HA Naming Service RMI
- 1102 UDP HA Naming Service AutoDiscovery
- 1161 UDP Snmp Agent Service
- 1162 UDP Trapd Service
- 3528 TCP IIOP Invoker
- 4447 TCP JRMPInvoker HA
- 45566 UDP Cluster Partition