Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Custom Security With a Spring Boot/Elide Json API Server

DZone's Guide to

Custom Security With a Spring Boot/Elide Json API Server

Here's a look at security permissions that are applicable to JPA entities, controlling attributes like reading, deletion, updating, and assignment of entities.

Free Resource

Transform incident management with machine learning and analytics to help you maintain optimal performance and availability while keeping pace with the growing demands of digital business with this eBook, brought to you in partnership with BMC.

In the last article, we looked at some simple security permissions that could be applied to JPA entities to allow or prevent the reading, creation, updating, deletion, and assignment of entities through relationships.

The built in Role.ALL and Role.NONE classes are useful for coarse-grained authorization but offer no ability to distinguish between users. A more likely scenario is one where privileged users can perform operations like create, delete, update and share, while all users can read entities.

The groundwork for providing different levels of access based on the user was laid down when we added authentication to the API. This provided us with a Principal object that has been passed into Elide’s various methods like get() and post().

In order to make use of this Principal to permit or deny actions based on who is logged in, we need to create a custom instance of the Elide UserCheck class.

package com.matthewcasperson.elidetest.permissions;

import com.yahoo.elide.security.User;
import com.yahoo.elide.security.checks.UserCheck;
import org.springframework.security.authentication.AbstractAuthenticationToken;

/**
 * A security check that passes for admin users
 */
public class AdminCheck extends UserCheck {
    @Override
    public boolean ok(User user) {
        final AbstractAuthenticationToken springUser = (AbstractAuthenticationToken) user.getOpaqueUser();
        return springUser.getAuthorities().stream()
                .anyMatch(a -> "ROLE_ADMIN".equalsIgnoreCase(a.getAuthority()));

    }
}

The AdminCheck class gets access to the opaque user object, which is the Principal that Spring injected into our REST API methods and we passed into the Elide get() and post() methods.

This opaque user object is then cast to a Spring AbstractAuthenticationToken object. AbstractAuthenticationToken implements the Java Principal interface, but exposes some additional information, like what roles have been assigned to the user via the getAuthorities() method. Converting this collection to a Java 8 stream and finding an admin role allows us to return true for admin users, and false for everyone else. If we return true, the security check passes, and the operation is allowed to succeed. Return false, and the operation will be blocked.

In order to give admin users full access to our API, while providing everyone else with read-only access, we need to assign our new class to the @SharePermission, @CreatePermission, @UpdatePermission and @DeletePermission annotations on our JPA entities.

The @ReadPermission annotation will still continue to reference the Role.ALL class.

@ReadPermission(any={ Role.ALL.class })
@SharePermission(any={ AdminCheck.class })
@CreatePermission(any={ AdminCheck.class })
@UpdatePermission(any={ AdminCheck.class })
@DeletePermission(any={ AdminCheck.class })

With this code in place, all users can read entities, but only admin users can make modifications.

Download the source code for this project from GitHub.

Evolve your approach to Application Performance Monitoring by adopting five best practices that are outlined and explored in this e-book, brought to you in partnership with BMC.

Topics:
json api ,spring ,rest api

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}