Close

Implementing “remember me” with Vaadin

One of the most common features for a login form is the remember me feature that allows users to be automatically signed in from a certain machine even after the HTTP session expires:

Screen Shot 2017-01-04 at 0.31.39.png

Web applications usually implement this feature by using cookies. When the user selects the remember me option and signs in, the application stores a cookie to identify the user. The next time the user requests the web application, the standard authentication process is skipped and the user is automatically logged in.

Never store sensitive information in cookies. It’s not safe to store, for example, the ID of the user. If an attacker knows a valid user ID, they can create a new cookie containing such ID and sign in as the impersonated user. In this example, I’m going to store a random string and associate it with a username in a HashMap. In real-world applications, you can use an SQL database, for example, and store not only a random ID, but the hash of a token similarly to what you should do with the user’s passwords.

Implementing the business logic

Let’s see how to do this with Vaadin 8. The first step is to implement a UserService class (or a UserRepository class) to encapsulate any logic related to user data persistence. This UserService class should provide methods to:

  • Authenticate the user (username and password check).

  • Store a remembered user.

  • Get a remembered user.

  • Remove a remembered user.

A remembered user in this example is a random id:username pair. The following is an example implementation of the UserService class:

public class UserService {

    private static SecureRandom random = new SecureRandom();

    private static Map<String, String> rememberedUsers
            = new HashMap<>();

    public static boolean isAuthenticUser(String username,
            String password) {
        return username.equals("admin")
                && password.equals("password");
    }

    public static String rememberUser(String username) {
        String randomId = new BigInteger(130, random).toString(32);
        rememberedUsers.put(randomId, username);
        return randomId;
    }

    public static String getRememberedUser(String id) {
        return rememberedUsers.get(id);
    }

    public static void removeRememberedUser(String id) {
        rememberedUsers.remove(id);
    }
}

Notice that for simplicity reasons, there’s no database connection and the isAuthentic method has only one hardcoded user (admin/password). You should implement your own database related logic depending on your specific persistence technologies. Notice also that the remembered users are stored in memory using a HashMap. Here again, you should use a database and implement the corresponding logic to persist and delete data.

Implementing the web-related logic

With a UserService like the previous one, you can implement the web related logic for authentication, that is, handling values in the HTTP session and cookies. This class should provide methods to:

  • Check whether a user is currently authenticated, either by the standard authentication mechanism or by the remember me functionality.

  • Login a certain user by credentials.

  • Logout the current user.

Of course, this class delegates user data manipulation to the UserService class. The following is an example implementation:

public class AuthService {

    private static final String COOKIE_NAME = "remember-me";
    public static final String SESSION_USERNAME = "username";

    public static boolean isAuthenticated() {
        return VaadinSession.getCurrent()
                .getAttribute(SESSION_USERNAME) != null
                        || loginRememberedUser();
    }

    public static boolean login(String username, String password,
            boolean rememberMe) {
        if (UserService.isAuthenticUser(username, password)) {
            VaadinSession.getCurrent().setAttribute(
                    SESSION_USERNAME, username);

            if (rememberMe) {
                rememberUser(username);
            }
            return true;
        }

        return false;
    }

    public static void logOut() {
        Optional<Cookie> cookie = getRememberMeCookie();
        if (cookie.isPresent()) {
            String id = cookie.get().getValue();
            UserService.removeRememberedUser(id);
            deleteRememberMeCookie();
        }

        VaadinSession.getCurrent().close();
        Page.getCurrent().setLocation("");
    }

    private static Optional<Cookie> getRememberMeCookie() {
        Cookie[] cookies =
                VaadinService.getCurrentRequest().getCookies();
        return Arrays.stream(cookies)
                .filter(c -> c.getName().equals(COOKIE_NAME))
                .findFirst();
    }

    private static boolean loginRememberedUser() {
        Optional<Cookie> rememberMeCookie = getRememberMeCookie();

        if (rememberMeCookie.isPresent()) {
            String id = rememberMeCookie.get().getValue();
            String username = UserService.getRememberedUser(id);

            if (username != null) {
                VaadinSession.getCurrent()
                        .setAttribute(SESSION_USERNAME, username);
                return true;
            }
        }

        return false;
    }

    private static void rememberUser(String username) {
        String id = UserService.rememberUser(username);

        Cookie cookie = new Cookie(COOKIE_NAME, id);
        cookie.setPath("/");
        cookie.setMaxAge(60 * 60 * 24 * 30); // valid for 30 days
        VaadinService.getCurrentResponse().addCookie(cookie);
    }

    private static void deleteRememberMeCookie() {
        Cookie cookie = new Cookie(COOKIE_NAME, "");
        cookie.setPath("/");
        cookie.setMaxAge(0);
        VaadinService.getCurrentResponse().addCookie(cookie);
    }
}

A user is considered authenticated if there’s an attribute in the HTTP session or if a cookie is present and valid. Notice how the login method accepts not only the credentials (username and password), but a flag indicating if the user should be remembered. Notice also how the cookie is removed when the user is logged out.

Implementing the UI

Implementing a Vaadin UI that uses this class is pretty straightforward. The simplest application to test this behavior should contain at least two “screens” or components. A public component (the login form) and a private component (the actual functionality of the application).

The Vaadin UI implementation couldn't be simpler:

public class VaadinUI extends UI {

    @Override
    protected void init(VaadinRequest vaadinRequest) {
        if (!AuthService.isAuthenticated()) {
            showPublicComponent();
        } else {
            showPrivateComponent();
        }
    }

    public void showPublicComponent() {
        setContent(new PublicComponent());
    }

    public void showPrivateComponent() {
        setContent(new PrivateComponent());
    }
}

The public component looks like this:

Screen Shot 2017-01-04 at 0.31.39.png

The interesting part of the implementation is the button’s ClickListener:

public class PublicComponent extends CustomComponent {

    public PublicComponent() {
        ...
        Button button = new Button(
                "Login",
                e -> onLogin(
                    username.getValue(),
                    password.getValue(),
                    rememberMe.getValue())
        );
        ...
    }

    private void onLogin(String username, String password,
            boolean rememberMe) {
        if (AuthService.login(username, password, rememberMe)) {
            VaadinUI ui = (VaadinUI) UI.getCurrent();
            ui.showPrivateComponent();
        } else {
            Notification.show(
                "Invalid credentials (for demo use: admin/password)",
                Notification.Type.ERROR_MESSAGE
            );
        }
    }
}

As you can see, the onLogin method uses the AuthService.login method to check if the user is authentic.

The private component is pretty simple as well. It shows a message with the username and a button to sign out:

Screen Shot 2017-01-04 at 0.31.49.png

The following is the full implementation:

public class PrivateComponent extends CustomComponent {

    public PrivateComponent() {
        String username = (String) VaadinSession.getCurrent()
                .getAttribute(AuthService.SESSION_USERNAME);

        Label label = new Label("Welcome, " + username);
        label.addStyleName(ValoTheme.LABEL_HUGE);

        Button button = new Button("Sign out", this::onLogout);

        setCompositionRoot(new VerticalLayout(label, button));
    }

    private void onLogout(Button.ClickEvent event) {
        AuthService.logOut();
    }
}

Nothing special about it. The username is read from the HTTP session and the logout button invokes the AuthService.logOut() method that removes the remember me cookie and invalidates the HTTP session.

You can find the full source code of this example on GitHub

Anastasia solves everyday problems with her team - it was love at first sight with Vaadin <3

Sometimes things just click. Anastasia is studying for a Master’s degree in Information Technology at the University of Turku and at the end of 2015 she was looking for an interesting topic to cover in her Bachelor’s thesis.

“My journey with Vaadin started with my Bachelor’s thesis, which was a Vaadin and GWT comparison. At that point I already realised that it would be great to connect my work life with Vaadin. A friend of mine pointed out that Vaadin was looking for an intern - and of course I took that chance and applied. So here I am now!” Anastasia says.

Vaadin Internship Program

The Vaadin internship lasted for 5 months, and gave students an opportunity to jumpstart their professional career with tech companies. The interning tech student gets introduced to Vaadin while working with diverse teams and the right team will be chosen depending on the intern’s studies and background.

“We went through a training project to understand the main features of Vaadin Framework. It also taught us to ask for help wherever it’s needed. Then, after the project completion I became part of the Vaadin Support team and I started to do the daily tasks our team does.” Anastasia sums up her onboarding at Vaadin.

Daily life on the Vaadin Support team

While working in the Vaadin Support team, Anastasia solves various issues, bugs, and tickets on a daily basis. Every day brings something new to fix or learn.

“Usually my day starts around 7am, but I arrive a little bit early to look through the updates and news. If I have left something from the previous day, I continue working on it right away, otherwise I check for new tasks. There is always something to do. One of the great things of Vaadin is the fact that we can spend some time on projects not directly related to our work, but which improve our skills and understanding. Also, there are always questions to answer on our forum and I can also learn something new from those questions.”

Vaadin gives the freedom to organise your working day and time flexibly which has enabled Anastasia to attend lectures at the university while doing the internship. “If I have lectures at the university I can go there and, if some tasks are left at work, I can go back to work after the lectures. It might sound like a lot of work to do and it is, but Vaadin takes into account that I am still a student and encourages me to study well. “

Vaadin is information, communication and technology

Vaadin is a multinational company with over 130 employees, of which most work at Vaadin HQ in Turku, Finland. “There are so many personalities and so much internal knowledge at Vaadin. It is really easy to ask anyone anything, and in case we don’t know within my team, there is someone else to ask from.”

After her internship, Anastasia was invited to join Vaadin as Junior Vaadin Developer and now she is working part-time. “You really get to do things at Vaadin.There is real team spirit and the possibility to contribute to Vaadin. Many thanks to my team and of course to my supervisor Maintenance Manager Tatu Lund.”

For the time-being, she does not have much free time but every now and then Anastasia dances. She loves to do dance choreography and salsa. She also loves reading, and her favorite writers are Dostoyevsky and Remarque.

Want to be like Anastasia?

Combine your love of Java technology with great colleagues? Take a look at the open opportunities at Vaadin and apply now!

Vaadin Jobs

Announcing new Vaadin Elements: vaadin-split-layout and vaadin-context-menu

Vaadin Elements has just launched <vaadin-split-layout> and <vaadin-context-menu> as two new freely available elements to our existing four. Vaadin Elements is a set of open source business class web components that bring structure and functionality to your web apps. vaadin-split-layout and vaadin-context-menu continue our trend of powerful, extensible web components.

We’ve also updated <vaadin-combo-box> with new features and fixes. Learn more in the release notes at the end of this post.

vaadin-split-layout 

<vaadin-split-layout> is a layout component that creates a customizable, resizable split between two elements. This element can be used for many different purposes, such as splitting a window for multitasking, for arranging different views on the same page, or for laying out pieces of information for an item.

Some of the features of <vaadin-split-layout> include:

  • Adjustable width/height of the layout with a draggable handle in between.
  • Vertical or horizontal split with the vertical property.
  • Can be nested to create more complex split layouts.
  • Customizable resize handle.
  • Emits resize notification.

Learn more about <vaadin-split-layout>  here.

vaadin-context-menu

This update also introduces the <vaadin-context-menu> component. <vaadin-context-menu> is a responsive web component for showing context dependent items for any element. This kind of context menu is often triggered with a right click or long tap and gives access to a menu suitable for that context. This can be used to supplement the existing browser context menu for your own unique context.

Some of the features of <vaadin-context-menu> include:

  • Customizable content can be either plain HTML or Polymer elements such as <paper-menu>.
  • Supports data-binding to the context and content.
  • Opens on both mouse and touch events. Can be set to open on any event, but defaults to your platform’s specific context opening trigger.
  • Automatic fullscreen mode for small viewports.
  • Both the contents and the overlay can be styled.
  • Provides both declarative HTML and imperative Javascript APIs.

 

Learn more about <vaadin-context-menu> here.

vaadin-combo-box release notes

<vaadin-combo-box> has received some love, too, and has new features and fixes.

  • Custom filtering lets the developer to bypass the built-in client-side filtering with a filter function of their own.
  • Remote filtering can asynchronously retrieve filtered items from a remote server.
  • Screenreader support has been improved.
  • selectedItem is no longer readOnly.

The Vaadin Elements team is committed to creating new, powerful web components.  As always, you can ask for questions and support on our forums or our Gitter chat.

Learn more at the Vaadin Elements homepage.