We are using PrincipalAware interface in our application to get some user related stuff.
I searched on the net to get the info about it with poor results, this is what I got on Google:
public interface PrincipalAware
Actions that want access to the Principal information from HttpServletRequest object should implement this interface.
This interface is only relevant if the Action is used in a servlet environment. By using this interface you will not become tied to servlet environment.
Please, help me to understand it.
The PrincipalAware interface allows the Struts to inject a PrincipalProxy object into the action instance. This proxy can be used to get access to the servlet security mechanism. Like this
public class MyAction extends ActionSupport implements PrincipalAware {
protected PrincipalProxy principal;
public void setPrincipalProxy(PrincipalProxy principalProxy) {
this.principal = principalProxy;
}
public PrincipalProxy getPrincipal() {
return principal;
}
}
Now, you can use PrincipalProxy in action method or on the view layer,
<s:if test="principal.isUserInRole('role1')">
Note, if you want to restrict an execution of some actions based on a role, then you could use roles interceptor.
Related
I am currently developing an API where I'm using DTO for the first time. So far I've used Spring's form validation with javax.validation.
So my question is if there is a way to combine both DTO and "form" validation. Let me explain myself: lets say I have a service to log in and another to register. In the service to register we have: name, password and email, the 3 of them must be filled. As for the login service, only the email and password must be filled. So we'd have something like:
private String name;
private String password;
private String email;
Until now, what I did was to create a POJO per request (forms) and then use annotations such as #NotNull but now with DTO in the project I'm in now they just have the same DTO and business object with the same properties and no constraints.
How could I do what I was usually doing? Checking the fields that must be not null in the controller looks a little dirty to me and I can't just put something like #NotNull in the UserDTO because then in the two examples I said I'd have to send also the name when logging in although it's not needed for that service.
So, how could I combine these 2 things? Is this something not possible or there's a better approach?
Thanks.
I assume you are using two separate controllers for login and register requests.
And if it is the case, then you can make good use of org.springframework.validation.Validator interface:
#Component("registrationValidator")
public class RegistrationValidatorImpl implements Validator {
#Override
public boolean supports(final Class<?> aClass) {
}
#Override
public void validate(final Object o, final Errors errors) {
}
}
Create RegistrationValidatorImpl and LoginValidatorIml and #Autowire it in your controllers.
The usage of validator is simple:
invokeValidator(registrationValidator, someDTO, errors);
if (errors.hasErrors()) {
return new ResponseEntity(HttpStatus.BAD_REQUEST); //or whatever logic here
}
The controller method signature should be similar to this:
#RequestMapping(value = "/register", method = RequestMethod.POST)
public ResponseEntity register(#RequestBody final SomeDTO someDTO, final HttpServletRequest request, final Errors errors) {}
I case of one controller, I assume you have different methods mapped to login and register requests. You can #Autowire both validators in controller and use each in separate methods.
Using groups for validation with javax.validation did the work. I followed the answer in this question (as Andrew suggested), then I just had to put every field I wanted to have different rules in different groups.
I have spring boot application which exposes REST endpoints protected by spring security.
I need to restrict access to some paths depending on service call. Let's say I have a service like this:
#Service
public class AccessService {
boolean hasAccess(String requestedPath) {
// some business logic here
}
}
The service will check user roles, some business conditions and return true or false.
Now I need to integrate this service call into my security configuration.
So far I have configuration like this:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
...
.and().authorizeRequests()
.anyRequest().hasRole("USER");
}
I see no way of adding the service call here (as it is completely static).
What I'm trying:
Currently I'm thinking of overriding my AuthenticationProvider and extending it with the additional functionality.
The other option would be to extend my REST controllers from a class which would do some sort of authorization, but I'm not sure if it is possible.
Question: How can I protect REST endpoints based on service method call? What is the proper way of doing that?
This is explained in the reference guide. Basically you need to use the access expression instead of the hasRole. You can then write powerful security expressions.
Something like the following should do the trick:
anyRequest()
.access("#accessService.hasAccess(request.requestURI) && hasRole('USER')");
This restricts access to user with the role ROLE_USER and which have access according to your own custom logic.
I think a good way to to this is to use #PreAuthorize
Some documentation can be found here: Expression-Based Access Control.
You are also able to add your own evaluator class/methods to customize to your specific needs:
#PreAuthorize("#customPermissionEvaluator.accessMethod(variable)")
Example class:
#Service(value = "customPermissionEvaluator")
public class CustomPermissionEvaluatorImpl implements CustomPermissionEvaluator {
#Override
public boolean accessMethod(int variable) {
if (variable == 1) {
return true;
}
return false;
}
}
I have recently started looking into Spring Integration as a result of this question and have a question about object-type based routing.
The application I am maintaining needs to process requests from an incoming ActiveMQ queue (request.queue) and send a response back to the caller on a topic (response.topic). At present the requests are structured as follows:
public abstract class Request {
// base class
}
public abstract class CustomerRequest extends Request {
// base class for customer-specific requests
}
public class FindCustomerByIdRequest extends CustomerRequest {
private int id;
}
public class FindAllCustomersRequest extends CustomerRequest {
private boolean includeArchivedCustomers;
}
public class AddCustomerRequest extends CustomerRequest {
private String name;
private Date signupDate;
private Address address;
}
I have a service for each high level domain object which provides the functionality to service these incoming requests:
#Service
public class CustomerService {
public CustomerResponse findCustomerById(FindCustomerByIdRequest request) {
// code snipped
return customerResponse;
}
public AddCustomerResponse addCustomer(AddCustomerRequest request) {
// code snipped
return addCustomerResponse;
}
}
I need to route each specific request to the approriate method in CustomerService via #ServiceActivator which I understand can be done by creating a separate channel for each request and implementing a PayloadTypeRouter to place requests on the correct channel based on type.
Over time the list of request types is going to grow, and I am questioning whether a one-channel-per-request setup is efficient/practical/scalable. For example, if there are 100 different request types in the future there are going to be 100 different channels.
What would be great is if I could route the high-level requests of superclass CustomerRequest to CustomerService and have Spring work out the approriate method to call via an annotation or some other mechanism. Does anyone know if this is possible, or have any comments regarding the many-channels approach?
If there is no ambiguity, use <service-activator ... reg="fooBean" /> (no method) and the framework will chose the target method based on the payload.
If there is ambiguity (more than one method for the same type), it will fail.
However, a single class with 100+ methods is probably not a good design.
It seems to be that your request types are app feature specific. This suggest that you have one queue for all the possible application features. That is horrible idea. You should have at least separate queue per feature.
I suggest to rethink the design of your app.
I am using spring & jersey2 to serve some rest-requests like:
#GET
#Path("/someservice")
#Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
public String getSomeStuff(...) {
login(...);
// ...
}
During a rest-request, I get an authorized user of the rest-request.
Now I need this user while updating or creating entities like:
#MappedSuperclass
public abstract class PersistentObject {
#PrePersist
#PreUpdate
public void onSaveOrUpdate() {
setCreationUser(...); // How to get the user of this session?
}
// ...
}
How can I get the current user of the rest-request there?
You can try to perform your login operation (for appropriate resource methods) in a ContainerRequestFilter and set SecurityContext:
#Provider
public class SecurityFilter implements ContainerRequestFilter {
#Override
public void filter(final ContainerRequestContext context) throws IOException {
final Principal user = login(...);
context.setSecurityContext(new SecurityContext() {
public Principal getUserPrincipal() {
return user;
}
// Other methods omitted.
});
}
}
Make sure you have jersey-spring3 module on your class-path and the Jersey-Spring integration allows you to inject SecurityContext into a Spring service:
#Service
public MySpringService implements MyService {
#Context
private SecurityContext context;
public String doStuff() {
final Principal user = context.getUserPrincipal();
// ...
}
}
You can't do this if the service, you want to use user principal in, is neither managed by Jersey nor Spring.
Spring Security might be useful to you in two ways:
It can manage authentication, (you would not need to do that login(...) call yourself, it would be done automatically by Spring Security filter chain. But you can still do it manually if you want.
Once a request has been authenticated, as long as the request is alive you can access the authenticated user from anywhere just by doing:
Authentication auth = SecurityContextHolder.getSecurityContext().getAuthentication();
// auth is an object that holds the authenticated user's data
I think you need some sort of authentication by the fact that you make a login(...) and you want to audit the user afterwards. You might not nedd an authentication form, but you do need authentication. Spring Security is not only for interactive applications, you can set up an authentication filter that does authentication based on cookies, request parameters, client certificates or whatever, all of that without user interaction.
Furthermore, Spring Security is very extensible, if you have your authentication method already implemented, integrating with Spring Security is easy. And it is also flexible: you don't need to use the security filter chain if it is too heavyweight for your use case. You can do most things manually and use just a little bit of Spring Security if you want.
I really suggest you take a deeper look at Spring docs about:
Spring Security core components overview and Spring Security authentication overview
I think with just that you will be able to get something working.
I want to create a base controller class that my other controllers will inherit from. I have a simple public api that takes the authentication token via the query string, so I want to do this:
public class MyBaseController {
private String token = "";
public MyBaseController() {
}
}
And then my real controller would be like:
#Controller
#RequestMapping("/api/users")
public class UserController extends MyBaseControler {
// controller methods here
}
My question is, how can i get access to the HttpServletRequest in my base controller, and get the querystring parameter "?token=abc123" value and set the token var with the value.
Is this thread safe? It is my understanding that there will be a new controller instance per request correct?
Your controllers are better off if they're stateless.
You can inject them with Spring services as needed, but I don't see any reason why they have to hang onto the value of the token as a member variable.
It's far more likely that you'll want to store the token in session scope. I think your idea is wrong-headed.
I'll point out that Spring itself has moved away from inheritance for controllers. They're all annotation-based now, with no common base class or interface. Why do you think devolving back to the design they abandoned is a good thing?
You don't need a base controller, either.