Für die Deklaration von Security brauchen wird xml-Dateien. Sei es die web.xml oder serverspezifische Konfigurationsdateien. So ist es lange Zeit gewesen. Bis jetzt. Java EE 8 weicht diese Feststellung nun auf und führt Interfaces ein, wie den HttpAuthenticationMechanism um die Deklaration dieser Regeln in den Code zu verlagern.
Java EE 8 liefert neben dem angesprochenen Interface (und weiterer) auch gleich drei passende Implementierungen mit:
- BasicAuthenticationMechanismDefinition
- FormAuthenticationMechanismDefinition
- CustomFormAuthenrticationMechanismDefinition
In diesem Beispiel widmen wir uns einem davon: FormAuthenticationMechanismDefinition. Die Idee ist einfach. Anstatt die Konfiguration in xml-Dateien vor zu nehmen, verwenden wir Annotationen um die Security-Regeln (an einer ApplicationScoped-Bean) zu deklarieren. Eine solche Deklaration könnte so aussehen:
@FormAuthenticationMechanismDefinition( loginToContinue = @LoginToContinue( loginPage = "/login.html", errorPage = "/error.html"))
Damit legen wir erst einmal nur fest wie der User seine Login-Informationen übergeben soll (nämlich über die login.html Datei). Ebenso spannend ist die Frage „Wie autorisiert unsere Anwendung einen User?“. Wer hätte es erwartet, auch hier liefert der JSR375 ein passendes Interface (IdentityStore) und entsprechende Implementierungen (DataBaseIdentityStoreDefinition, LdapIdentityStoreDefinition).
@DatabaseIdentityStoreDefinition( dataSourceLookup = "java:jboss/datasources/DemoDS", callerQuery = "select PASSWORD from USER where USERNAME=?", groupsQuery = "select GROUPNAME from USERGROUPS where USERNAME=?", hashAlgorithm = de.gedoplan.PlainTextPasswordHash.class ) @ApplicationScoped public class ApplicationSecurityConfig {}
Hier geben wir an welche Datasource und Queries verwendet werden sollen um einen Benutzer zu validieren und dessen Benutzergruppen aus zu lesen. Zusätzlich muss hier eine PasswordHash-Implementierung angegeben werden (javax.security.enterprise.identitystore.PasswordHash). Mit Pbkdf2PasswordHash wird eine Implementierung mitgeliefert, das Beispiel oben verwendet eine eigene Implementierung welche die Passwörter in Klartext in der Datenbank ablegt (don’t do this at home).
Das war es schon ( fast ) jetzt können wir unsere Resourcen mit entsprechenden Berechtigungen versehen. Hier in Kürze 3 Varianten:
Servlets:
@WebServlet(urlPatterns = "/servlet") @ServletSecurity(@HttpConstraint(rolesAllowed = "ADMIN")) public class DemoServlet extends HttpServlet{...}
JAX-RS, Rest Webservices
@Path("demo") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Stateless public class DemoResource { @GET @PermitAll public DemoModel getDemo() {...} @GET @Path("admin") @RolesAllowed("ADMIN") public DemoModel getAdminDemo() {...} }
Webseiten über web.xml (dann doch noch mal xml)
<security-constraint> <web-resource-collection> <web-resource-name>Protected user resource/url</web-resource-name> <url-pattern>/secured/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>ADMIN</role-name> <role-name>USER</role-name> </auth-constraint> </security-constraint>
Das wars. Alles. Live. In Farbe:
https://github.com/GEDOPLAN/jee8-security
Anmerkung zur Verwendung von Wildfly:
Das gezeigte Feature muss durch die Aktivierung der Security-Domain „jaspitest“ erst aktiviert werden (ab Wildfly 10)
(in der jboss-web.xml<jboss-web> <security-domain>jaspitest </jboss-web>)
Hier auch eine Anleitung für andere Versionen: click