Expand Authors Top

If you have a few years of experience in the Java ecosystem and you’d like to share that with the community, have a look at our Contribution Guidelines.

November Discount Launch 2022 – Top
We’re finally running a Black Friday launch. All Courses are 30% off until next Friday:

>> GET ACCESS NOW

Expanded Audience – Frontegg – Security (partner)
announcement - icon User management is very complex, when implemented properly. No surprise here.

Not having to roll all of that out manually, but instead integrating a mature, fully-fledged solution - yeah, that makes a lot of sense.
That's basically what Frontegg is - User Management for your application. It's focused on making your app scalable, secure and enjoyable for your users.
From signup to authentication, it supports simple scenarios all the way to complex and custom application logic.

Have a look:

>> Elegant User Management, Tailor-made for B2B SaaS

NPI – Frontegg – Security – (partner)
announcement - icon User management is very complex, when implemented properly. No surprise here.

Not having to roll all of that out manually, but instead integrating a mature, fully-fledged solution - yeah, that makes a lot of sense.
That's basically what Frontegg is - User Management for your application. It's focused on making your app scalable, secure and enjoyable for your users.
From signup to authentication, it supports simple scenarios all the way to complex and custom application logic.

Have a look:

>> Elegant User Management, Tailor-made for B2B SaaS

1. Overview

In this tutorial, we'll illustrate how to use Run-As authentication in Spring Security with a simple scenario.

The very high-level explanation about Run-As is as follows: a user can execute some piece of logic as another principal with different privileges.

2. The RunAsManager

The first thing we'll need to do is set up our GlobalMethodSecurity and inject a RunAsManager.

This is responsible for providing the temporary Authentication object with extra privileges:

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    @Override
    protected RunAsManager runAsManager() {
        RunAsManagerImpl runAsManager = new RunAsManagerImpl();
        runAsManager.setKey("MyRunAsKey");
        return runAsManager;
    }
}

By overriding runAsManager, we're replacing the default implementation in the base class – which simply returns a null.

Also notice the key property – the framework uses that to secure/verify temporary Authentication objects (created via this manager).

Finally – the resulting Authentication object is a RunAsUserToken.

3. Security Configuration

To authenticate our temporary Authentication object, we'll set up a RunAsImplAuthenticationProvider:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    ...
    auth.authenticationProvider(runAsAuthenticationProvider());
}

@Bean
public AuthenticationProvider runAsAuthenticationProvider() {
    RunAsImplAuthenticationProvider authProvider = new RunAsImplAuthenticationProvider();
    authProvider.setKey("MyRunAsKey");
    return authProvider;
}

We're of course setting this up with the same key we used in the manager – so that the provider can check that the RunAsUserToken authentication object is created using the same key.

4. The Controller With @Secured

Now – let's see how to use Run-As Authentication replacement:

@Controller
@RequestMapping("/runas")
class RunAsController {

    @Secured({ "ROLE_USER", "RUN_AS_REPORTER" })
    @RequestMapping
    @ResponseBody
    public String tryRunAs() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return "Current User Authorities inside this RunAS method only " + 
          auth.getAuthorities().toString();
    }

}

The core thing here is the new role – RUN_AS_REPORTER. This is the trigger of the Run-As functionality – as the framework deals with it differently because of the prefix.

When a request executes through this logic, we'll have:

  • The current user authorities before tryRunAs() method are [ROLE_USER]
  • The current user authorities inside tryRunAs() method are [ROLE_USER, ROLE_RUN_AS_REPORTER]
  • The temporary Authentication object replaces the existing Authentication object for the duration of the tryRunAS() method invocation only

5. The Service

Finally, let's implement the actual logic – a simple service layer that's also secured:

@Service
public class RunAsService {

    @Secured({ "ROLE_RUN_AS_REPORTER" })
    public Authentication getCurrentUser() {
        Authentication authentication = 
          SecurityContextHolder.getContext().getAuthentication();
        return authentication;
    }
}

Note that:

  • To access getCurrentUser() method, we need to ROLE_RUN_AS_REPORTER
  • So we can only call getCurrentUser() method inside our tryRunAs() controller method

6. The Front-End

Next, we will use a simple front-end to test our Run-As feature:

<html>
<body>
Current user authorities: 
    <span sec:authentication="principal.authorities">user</span>
<br/>
<span id="temp"></span>
<a href="#" onclick="tryRunAs()">Generate Report As Super User</a>
             
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script type="text/javascript">
function tryRunAs(){
    $.get( "/runas" , function( data ) {
         $("#temp").html(data);
    });
}
</script>
</body>
</html>

So now, when a user triggers the “Generate Report As Super User” action – they'll obtain the temporary ROLE_RUN_AS_REPORTER authority.

7. Conclusion

In this quick tutorial, we explored a simple example using the Spring Security Run-As authentication replacement feature.

This tutorial is based on the codebase available on GitHub.

November Discount Launch 2022 – Bottom
We’re finally running a Black Friday launch. All Courses are 30% off until next Friday:

>> GET ACCESS NOW

Security footer banner
Comments are closed on this article!