November 10, 2020
This article shows how to set up a minimal Basic Authenticationmd scheme in WildFly to protected RESTful web services. The example uses the ApplicationRealm that ships with WildFly.
The JavaEE code described this article is on GitHub.
Basic Authentication is standard in JavaEE. As an application developer, you set up security-constraints in your web.xml that protects url-patterns. In the case of a RESTful API, these url-patterns map to JAX-RS web services. Your login-config element will tell which type of authentication to use such as "BASIC". login-config will also set the realm-name which references a Realm set up in the app server (WildFly).
The demo application has a pair of RESTful web services, PublicResource and ProtectedResource. PublicResource has open access. There are no constraints on it. ProtectedResource is subject to a constraint. This constraint requires that the request accessing ProtectedResource has a credential given the role "user".
The credentials are managed by WildFly in a Realm that ships with the app server called "ApplicationRealm". ApplicationRealm is a simple properties file-based store I find useful to quickly secure services under development. Real-world applications will use a more sophisticated Realm backed by a database or LDAP.
This UML diagram shows the relationship between the code -- packaged in a WAR called bekwam-security-examples-basic-auth.war -- and the configuration. The configuration includes the web.xml added to the WAR as well as the ApplicationRealm set up in WildFly.
The following fragment from web.xml shows the configuration relating the url-pattern of the ProtectedResource to the role "user".
<security-constraint> <web-resource-collection> <web-resource-name>Protected page</web-resource-name> <url-pattern>/api/protected</url-pattern> </web-resource-collection> <auth-constraint> <role-name>user</role-name> </auth-constraint> </security-constraint>
role-name needs to be defined as a security-role. (This security-role can be used in other definitions.)
<security-role> <role-name>user</role-name> </security-role>
The per-WAR authentication method needs to be defined. This is set to Basic Authentication and will go against the app server-provided Realm "ApplicationRealm".
<login-config> <auth-method>BASIC</auth-method> <realm-name>ApplicationRealm</realm-name> </login-config>
To this point, the code and web.xml configuration has been standard Java EE. The following procedures describe how to define a Realm in the WildFly app server. This example is the simplest since it uses an ApplicationRealm that is ready out-of-the-box.
Take a look at the WildFly config file (most likely standalone.xml or standalone-full.xml) at the ApplicationRealm and how it's used. You'll see it appear as a properties-realm definition. It's referenced in other places, but the properties-realm is all that is needed for this demo.
The ApplicationRealm that ships with WildFly is a PropertiesRealm. A PropertiesRealm uses a pair of flat files to manage users and credentials (application-users.properties) and roles (application-roles.properties). WildFly ships with a tool called add-user.sh which is a CLI that puts the correct entries in both files.
The following are the contents of the application-users.properties and application-roles.properties file after the add-user.sh command is run.
# application-users.properties carlw=4e02237a137589db116a8afeb7924f95 # application-roles.properties carlw=user
If multiple roles are assigned, there will be multiple values associated with the user in application-roles.properties.
To run add-user.sh, change into the $WILDFLY_HOME/bin folder. Step through the instructions providing the username, a password credential, and one or more roles. In this example the role "user" is required to be able to work with ProtectedResource.
The result of add-user.sh is a line in application-users.properties and a line in application-roles.properties. In application-users.properties, the line is a username / credential pair. The credential is stored as an MD5 hash of Realm : Username : Password (ex
md5('ApplicationRealm:carlw:abc123')). The role is a username / role mapping.
If you need to deploy something quickly, say to give front-end developers something to work with, you can quickly secure your services with a username and password stored in the out-of-the-box ApplicationRealm. Eventually, you'll transition to a more robust and expressive Realm. However, it's important to start thinking about security right at the start of the project. The roles that you define in this interim solution can carry over to later project stages.
By Carl Walker
President and Principal Consultant of Bekwam, Inc