In this tutorial we will learn how to configure HTTP basic authentication with WildFly.
Basic authentication is a simple authentication policy built into the HTTP protocol. The client sends an HTTP request with the Authorization header that contains the word Basic word followed by a space and a base64-encoded string username:password.
As an example, in order to authorize as demo / [email protected] the client would send
Authorization: Basic ZGVtbzpwQDU1dzByZA==
Note: Because base64 is easily decoded, Basic authentication should only be used together with other security mechanisms such as HTTPS/SSL.
Example: enabling HTTP Basic Authentication in WildFly
In order to enable HTTP Basic Authentication in WildFly we will define a Security Realm with Elytron. The most basic example of a security realm is the FileSystem Realm, which stores the identity information on a filesystem, by paging each identity in an XML file containing credentials and Roles. Start the application server and connect to it from a CLI (jboss-cli.sh). Then execute the following commands:
# add a Simple Role Decoder which maps the application Roles from the attribute Roles in the File system. if (outcome != success) of /subsystem=elytron/simple-role-decoder=from-roles-attribute:read-resource /subsystem=elytron/simple-role-decoder=from-roles-attribute:add(attribute=Roles) end-if batch # Let’s define a new filesystem-realm named fsRealm and its respective path on the file system: /subsystem=elytron/filesystem-realm=demoFsRealm:add(path=demofs-realm-users,relative-to=jboss.server.config.dir) # Next, we add some identities to the Realm: /subsystem=elytron/filesystem-realm=demoFsRealm:add-identity(identity=frank) /subsystem=elytron/filesystem-realm=demoFsRealm:set-password(identity=frank,clear={password="password123"}) /subsystem=elytron/filesystem-realm=demoFsRealm:add-identity-attribute(identity=frank,name=Roles, value=["Admin","Guest"]) # Create a new Security Domain which maps our Realm: /subsystem=elytron/security-domain=fsSD:add(realms=[{realm=demoFsRealm,role-decoder=from-roles-attribute}],default-realm=demoFsRealm,permission-mapper=default-permission-mapper) # We need an Http Authentication Factory which references our Security Domain: /subsystem=elytron/http-authentication-factory=example-fs-http-auth:add(http-server-mechanism-factory=global,security-domain=fsSD,mechanism-configurations=[{mechanism-name=BASIC,mechanism-realm-configurations=[{realm-name=RealmUsersRoles}]}]) # Finally, a Security Domain in the undertow’s subsystem will be associated with our Http Authentication Factory: /subsystem=undertow/application-security-domain=FSSecurityDomain:add(http-authentication-factory=example-fs-http-auth) run-batch reload
Then set the security domain in “jboss-web.xml“:
<jboss-web xmlns="http://www.jboss.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.jboss.org/schema/jbossas http://www.jboss.org/schema/jbossas/jboss-web_7_2.xsd"> <security-domain>FSSecurityDomain</security-domain> </jboss-web>
And configure th auth-method in your web.xml:
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"> <login-config> <auth-method>BASIC</auth-method> <realm-name>RealmUsersRoles</realm-name> </login-config> </web-app>
Our application defines a single endpoint, which has an HttpConstraint allowing access only to “Admin” users:
@WebServlet("/secure") @ServletSecurity(@HttpConstraint(rolesAllowed = { "Admin" })) public class SecuredServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); Principal principal = null; String authType = null; String remoteUser = null; principal = req.getUserPrincipal(); remoteUser = req.getRemoteUser(); authType = req.getAuthType(); writer.println("servlet-security"); writer.println("Successfully called Secured Servlet"); writer.println("Principal : " + principal.getName() + "); writer.println("Remote User : " + remoteUser + "); writer.println("Authentication Type : " + authType + "); writer.println(""); writer.close(); } }
Let’s send a request to the secured endpoint:
curl -u frank:password123 http://localhost:8080/http-basic/secure Successfully called Secured Servlet Principal : frank Remote User : frank Authentication Type : BASIC
You can find the souce code for this example here: https://github.com/fmarchioni/mastertheboss/tree/master/security/http-basic
Setting HTTP Basic authentication for Web Services
In case you are using EJB-based Web Services the configuration is slightly different; because the security domain is not specified into the web descriptors, we have to provide it by means of annotations:
@Stateless @WebService(targetNamespace = "https://www.mastertheboss.com/", serviceName = "SecureService") @WebContext(authMethod = "BASIC", secureWSDLAccess = false) @SecurityDomain(value = "other") public class SecureEJB { }
As you can see, the @WebContext annotation basically reflects the same configuration options of POJO-based Web Services, with BASIC authentication and unrestricted WSDL access.
Basic authentication using Database
If you want to learn how to configure authentication using a Database instead of a property file, check this tutorial: Configure an Elytron JDBC Realm on WildFly