Over a million developers have joined DZone.

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.

Discover 50 of the latest mobile performance statistics with the Ultimate Guide to Digital Experience Monitoring, brought to you in partnership with Catchpoint.

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.

Is your APM strategy broken? This ebook explores the latest in Gartner research to help you learn how to close the end-user experience gap in APM, brought to you in partnership with Catchpoint.

Topics:
json api ,spring ,rest api

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

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

{{ parent.tldr }}

{{ parent.urlSource.name }}