Webapplicatie met Spring Security
Beveiligen van een webapplicatie is iets wat altijd gedaan dient te worden. Nu weten we allemaal dat het aardig wat werk is om keer op keer een autorisatie- en authenticatiemechanisme te maken inclusief bijbehorende filters die er voor zorgen dat men niet direct bij een beveiligde url kan komen. Een oplossing is Spring Security.
Een aantal stappen moeten genomen worden om Spring Security in te zetten:
Configuratie
De web.xml configureren met de juiste filter en filter mapping:
contextConfigLocation
WEB-INF/applicationContext.xml
springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy
springSecurityFilterChain
Hierboven staat een contextConfigLocation, hier staat de locatie van de Spring applicationContext. In deze context wordt aangeven wat voor soort beveiliging wordt gebruikt, in dit geval http security met een login-form. Het access-denied-page attribuut definieert de pagina welke de gebruiker getoond krijgt indien deze niet de juiste rol bezit voor de opgevraagde pagina. De intercept-url tags geven aan welke urls er onderschept moeten worden en welke rol benodigd is om deze te mogen zien. URLS naar resources zoals javascript, images en stylesheets worden in dit voorbeeld toegankelijk gemaakt voor anonieme gebruikers zodat deze altijd zichtbaar en benaderbaar zijn.
Onder de url interceptors staat de tag security-form-login. De attributen van deze tag hebben de volgende betekenis:
* always-use-default-target – Dit zorgt ervoor dat er altijd na inloggen doorverwezen wordt naar de pagina die geconfigureerd staat in het default-target-url attribuut.
* login-processing-url: Dit url waarnaar de filter zal “luisteren” voor het verkrijgen van inloggegevens. Deze url wordt gebruikt in een redirect in de implementatie (hier later meer over).
* login-page: De pagina die getoond wordt om in te loggen. Als er direct naar een url wordt gegaan zonder dat de gebruiker is ingelogd zorgt de filter ervoor dat de gebruiker doorverwezen wordt naar de inlog pagina.
* Als laatste staat er nog de security:logout logout-success-url, dit is de url waarnaar de gebruiker doorverwezen wordt na een succesvolle uitlog aanroep.
Omdat ook de gebruikersgegevens opgehaald moet worden moeten er nog twee beans toegevoegd worden:
Implementatie
De bean met id ‘userDetailsService’ in bovenstaande Spring configuratie verwijst naar een implementatie van de userDetailsService. Dit is een interface vanuit het Spring security framework die geïmplementeerd dient te worden. De andere bean is het de DAO implementatie die wordt gebruikt om de database te benaderen vanuit de userDetailsService.
Hieronder de code van de userDetailsService:
import org.springframework.dao.DataAccessException;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.userdetails.UsernameNotFoundException;
public class UserDetailsServiceImpl implements UserDetailsService {
private UserDao userDao;
public UserDetailsServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
AppUser user = userDao.findUser(username);
if (user == null)
throw new UsernameNotFoundException("Gebruiker niet gevonden: " + username);
else {
return makeUser(user);
}
}
private org.springframework.security.userdetails.User makeUser(AppUser user) {
return new org.springframework.security.userdetails.User(user.getLogin(), user.getPassword(), true, true, true, true,
makeGrantedAuthorities(user));
}
private GrantedAuthority[] makeGrantedAuthorities(AppUser user) {
GrantedAuthority[] result = new GrantedAuthority[user.getRoles().size()];
int i = 0;
for (String role : user.getRoles()) {
result[i++] = new GrantedAuthorityImpl(role);
}
return result;
}
}
UserDao is een Dao implementatie die ervoor zorgt dat de gegevens uit de database gehaald worden en in een pojo, die de gebruikers details bevat, gezet worden zodat deze in de gehele applicatie te gebruiken zijn. Als laatste moet de inlogpagina en de bijbehorende backingbean gemaakt worden.
De inlog pagina:
Inloggen;
en bijbehorende backingbean
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.security.ui.AbstractProcessingFilter;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import mandaatkracht.EncodingUtils;
public class LoginBean {
// properties
private String userId;
private String password;
/**
* default empty constructor
*/
public LoginBean() {
Exception ex = (Exception) FacesContext
.getCurrentInstance()
.getExternalContext()
.getSessionMap()
.get(AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY);
if (ex != null)
FacesContext.getCurrentInstance().addMessage(
null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, ex
.getMessage(), ex.getMessage()));
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public void login(ActionEvent e) {
try {
FacesContext.getCurrentInstance().getExternalContext().redirect("/Application/j_spring_security_check?j_username=" + userId + "&j_password=" + EncodingUtils.encodeMD5(password) );
} catch (Exception ex) {
Logger.getLogger(LoginBean.class.getName()).log(Level.SEVERE, null, ex);
ex.printStackTrace();
}
}
}
De pagina is eenvoudig. De velden Gebruikersnaam en wachtwoord binden aan de backingbean. Op het moment dat er op de knop inloggen wordt gedrukt wordt er een redirect gedaan naar de /j_spring_security_check. Dit is de url waarop de filter reageert. Indien correcte inlog gegevens verstuurd worden zal de filter de gebruiker doorsturen naar een andere pagina. Zijn de inloggegevens incorrect dan zal er een foutmelding getoond worden. In de gehele applicatie kan gebruik gemaakt worden van de gebruikersrollen of gebruikersnaam met bijvoorbeeld de attributen:
renderedOnUserRole=”ROLE_ADMIN” of
Uitloggen
Het uitloggen is ook eenvoudid te realiseren. Het filter “luisterd” standaard naar de url j_spring_security_logout. Het enige dat gedaan moet worden is een redirect naar die url:
public void logout(ActionEvent e) throws java.io.IOException {
FacesContext.getCurrentInstance().getExternalContext().redirect("/Application/j_spring_security_logout");
}
De filter zal de gebruiker automatisch doorverwijzen naar de pagina die bij de eerder besproken security:logout logout-success-url tag staat.

Comments are closed.