I'm new to Vaadin. Before this I made a JSF Web Application. I had a ManagedBean performing the login of the user. I used a security-realm to delegate the actual verification of the credentials.
How do I do this in Vaadin? Is there a best practice? I'm at a point where I would just put something together, but there has to be some kind of standard-procedure, shouldn't it!? I found some tutorials on this, but mostly using Spring (I want to use EJB). Also, every tutorial seemed unneccessary complicated.
There has to be some simple+conclusive tutorial for something so common.
Here is the only Vaadin official article about how to secure a Vaadin aplication using JAAS that I could find. I mean native or official Vaadin Securization. You will find more if you google a little bit with Spring security, Shiro, but pure ESB uses JAAS. I agree that this article is not enough to learn how to set up an application. I share here my experience:
1. Vaadin CDI extension:
<!-- Vaadin Official DI support. -->
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-cdi</artifactId>
<version>1.0.0.alpha2</version>
</dependency>
2. Understanding about JAAS
I suggest you to have a look how JAAS works in a non-vaadin application, by reading overview articles, because JAAS depends on Server application provider (TomEE,Jboss, Wildfly, Glasfish) all have different configuration settings. Here you will find a proof of concept using Tomee.
3. Developing your own Login Module.
If you have decided to create a custom login module for example:
public class MyLoginModule implements LoginModule {
private CallbackHandler handler;
private Subject subject;
private UserPrincipal userPrincipal;
private RolePrincipal rolePrincipal;
private String login;
private List<String> userGroups;
@Override
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
Map<String, ?> options) {
handler = callbackHandler;
this.subject = subject;
}
@Override
public boolean login() throws LoginException {
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("login");
callbacks[1] = new PasswordCallback("password", true);
try {
handler.handle(callbacks);
String name = ((NameCallback) callbacks[0]).getName();
String password = String.valueOf(((PasswordCallback) callbacks[1]).getPassword());
// Here we validate the credentials against some
// authentication/authorization provider.
// It can be a Database, an external LDAP, a Web Service, etc.
// For this tutorial we are just checking if user is "user123" and
// password is "pass123"
if (name != null && name.equals("admin") && password != null && password.equals("admin")) {
login = name;
userGroups = new ArrayList<String>();
userGroups.add("admin");
return true;
}
// If credentials are NOT OK we throw a LoginException
throw new LoginException("Authentication failed");
} catch (IOException e) {
throw new LoginException(e.getMessage());
} catch (UnsupportedCallbackException e) {
throw new LoginException(e.getMessage());
}
}
@Override
public boolean commit() throws LoginException {
userPrincipal = new UserPrincipal(login);
subject.getPrincipals().add(userPrincipal);
if (userGroups != null && userGroups.size() > 0) {
for (String groupName : userGroups) {
rolePrincipal = new RolePrincipal(groupName);
subject.getPrincipals().add(rolePrincipal);
}
}
return true;
}
@Override
public boolean abort() throws LoginException {
return false;
}
@Override
public boolean logout() throws LoginException {
subject.getPrincipals().remove(userPrincipal);
subject.getPrincipals().remove(rolePrincipal);
return true;
}
}
Reference it in the META-INF/context.xml of your application. This settings are for TomEE, but for glashfish or other must be similar.
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Realm className="org.apache.catalina.realm.JAASRealm" appName="myrealm" userClassNames="net.sf.jaas.auth.UserPrincipal"
roleClassNames="net.sf.jaas.auth.RolePrincipal" />
</Context>
Be aware that userClassNames and roleClassNames are just simple Java Pojo but must implement java.security.Principal;
3. Enabling JAAS into your Vaadin Login View
Define your favourite login form, using Vaadin TextField and Password, and define in your doLoginEvent() a references to JAAS. Whenever JaasAccessControl.login is called, a new instance of your LoginModule will be created.
import com.vaadin.cdi.access.JaasAccessControl;
try {
JaasAccessControl.login(loginEvent.getUsername(), loginEvent.getPassword());
logger.info("User {} authenticated", getPrincipalName());
navigator.navigateTo(Main.NAME);
} catch (Exception e) {
Notification.show("Error logging in", Type.ERROR_MESSAGE);
logger.error(e.getMessage(), e);
}
4. Using information of your logged user.
Whenever a user passes the JAAS login filter. It will be available in his request context a class that identifies him. This class is called Principal (the one you have previously set in the LoginModule class).
public boolean isUserInRole(String role) {
return JaasAccessControl.getCurrentRequest().isUserInRole(role);
}
public String getPrincipalName() {
Principal principal = JaasAccessControl.getCurrentRequest().getUserPrincipal();
if (principal != null) {
return principal.getName();
}
return null;
}
public boolean isUserSignedIn() {
Principal principal = JaasAccessControl.getCurrentRequest().getUserPrincipal();
return principal != null;
}
5. Alternatives to LoginModule
It's not mandatory to create your custom login Module, normally the Java EE providers as Tomee supply few implementation. Authentication based on properties file, in some database tables. Have a look on Tomee documentation JAAS to see some examples:
6. Enable JAAS in TomEE You need to create a jaas.config file which references you LoginModule, for example:
filename: jaas.config
myrealm{
net.sf.jaas.MyLoginModule required;
};
Then start the application server with this parameter:
-Djava.security.auth.login.config=E:/apache-tomee-jaxrs-1.6.0.2/conf/jaas.config
If you want to have a look a proof of concept of this. Checkout this example, which uses Tomee, Vaadin 7, JAAS,
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With