Injected Bean is null in my quarkus extension - java

I have a quite simple quarkus extension which defines a ContainerRequestFilter to filter authentication and add data to a custom AuthenticationContext.
Here is my code:
runtime/AuthenticationContext.java
public interface AuthenticationContext {
User getCurrentUser();
}
runtime/AuthenticationContextImpl.java
#RequestScoped
public class AuthenticationContextImpl implements AuthenticationContext {
private User user;
#Override
public User getCurrentUser() {
return user;
}
public void setCurrentUser(User user) {
this.user = user;
}
}
runtime/MyFilter.java
#ApplicationScoped
public class MyFilter implements ContainerRequestFilter {
#Inject
AuthenticationContextImpl authCtx;
#Override
public void filter(ContainerRequestContext requestContext){
// doing some stuff like retrieving the user from the request Context
// ...
authCtx.setCurrentUser(retrievedUser)
}
}
deployment/MyProcessor.java:
class MyProcessor {
//... Some stuff
#BuildStep
AdditionalBeanBuildItem createContext() {
return new AdditionalBeanBuildItem(AuthenticationContextImpl.class);
}
}
I have a Null Pointer Exception in authCtx.setCurrentUser(retrievedUser) call (authCtx is never injected)
What am I missing here ?
Thanks

Indexing the runtime module of the extension fixes the problem.
There are multiple ways to do that as mentioned in https://stackoverflow.com/a/55513723/2504224

Related

Spring security pass SecurityExpressionRoot to custom method

I want to pass SecurityExpressionRoot class, which i can access inside #PreAuthorise() annotation, to my custom checkAccess() method which checks access to specific method, using some logic based on authorities, roles and a additional variables that i pass to this method.
Inside #PreAuthorise() I can access methods from SecurityExpressionRoot, for example. hasAuthority()
Is there any way to do that?
Controller:
public class TestController {
private final PreAuthorizeChecker preAuthorizeChecker;
#Autowired
public TestController(PreAuthorizeChecker preAuthorizeChecker) {
this.preAuthorizeChecker = preAuthorizeChecker;
}
#GetMapping(path = "/test")
#PreAuthorize("#preAuthorizeChecker.checkAccess(/*SecurityExpressionRoot.getSomehow()*/)") //How to obtain SecurityExpressionRoot instance?
public ResponseEntity<Void> get() {
return;
}
PreAuthorizeChecker:
#Component
public class PreAuthorizeChecker {
#Autowired
public PreAuthorizeChecker() {
}
public boolean checkAccess(SecurityExpressionRoot securityExpressionRoot) {
//do sth with securityExpressionRoot
return true;
}
}
You might find that part 5 of this blog, A Custom Security Expression with Spring Security, on Baelding.com helpful. The author suggests extending SecurityExpressionRoot and adding your custom method to the new class like this:
public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
public CustomMethodSecurityExpressionRoot(Authentication authentication) {
super(authentication);
}
public boolean checkAccess() {
//do sth with securityExpressionRoot
return true;
}
...
}
Then you will need to inject that new class into the expression handler like this:
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
#Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
return root;
}
}
Finally, you just need to create the expression handler in your security config like this:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
CustomMethodSecurityExpressionHandler expressionHandler = new CustomMethodSecurityExpressionHandler();
return expressionHandler;
}
}
Then your new expression should be available:
#PreAuthorize("checkAccess()")
public ResponseEntity<Void> get() {
return;
}

How to retrieve SecurityContext in a Quarkus application?

I have a Quarkus application in which I implemented the ContainerRequestFilter interface to save a header from incoming requests:
#PreMatching
public class SecurityFilter implements ContainerRequestFilter {
private static final String HEADER_EMAIL = "HD-Email";
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
String email = requestContext.getHeaders().getFirst(HEADER_EMAIL);
if (email == null) {
throw new AuthenticationFailedException("Email header is required");
}
requestContext.setSecurityContext(new SecurityContext() {
#Override
public Principal getUserPrincipal() {
return () -> email;
}
#Override
public boolean isUserInRole(String role) {
return false;
}
#Override
public boolean isSecure() {
return false;
}
#Override
public String getAuthenticationScheme() {
return null;
}
});
}
}
In a class annotated with ApplicationScoped I injected the context as follows:
#ApplicationScoped
public class ProjectService {
#Context
SecurityContext context;
...
}
The problem is that the context attribute is actually never injected, as it is always null.
What am I doing wrong? What should I do to be able to retrieve the SecurityContext throughout the application's code?
I like to abstract this problem, so that the business logic does not depend on JAX-RS-specific constructs. So, I create a class to describe my user, say User, and another interface, the AuthenticationContext, that holds the current user and any other authentication-related information I need, e.g.:
public interface AuthenticationContext {
User getCurrentUser();
}
I create a RequestScoped implementation of this class, that also has the relevant setter(s):
#RequestScoped
public class AuthenticationContextImpl implements AuthenticationContext {
private User user;
#Override
public User getCurrentUser() {
return user;
}
public void setCurrentUser(User user) {
this.user = user;
}
}
Now, I inject this bean and the JAX-RS SecurityContext in a filter, that knows how to create the User and set it into my application-specific AuthenticationContext:
#PreMatching
public class SecurityFilter implements ContainerRequestFilter {
#Inject AuthenticationContextImpl authCtx; // Injecting the implementation,
// not the interface!!!
#Context SecurityContext securityCtx;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
User user = ...// translate the securityCtx into a User
authCtx.setCurrentUser(user);
}
}
And then, any business bean that needs the user data, injects the environment-neutral, application-specific AuthenticationContext.
#Context can only be used in JAX-RS classes - i.e. classes annotated with #Path.
In your case, ProjectService is a CDI bean, not a JAX-RS class.
The canonical way to do what you want is to inject the SecurityContext into a JAX-RS resource and then pass that as a method parameter to your ProjectService

Replace switch-case with polymorphism

I know there are similar questions already, but looking at them I still have some doubts about how I should design my code. I have a service that allows for User registration / login /update / delete. The thing is that the User is an abstract type, which contains the data typeOfUser based on which the actual registration / update / delete methods should be called, and right now I do that in a switch-case block. I'd like to replace that with some better design.
UserController.java
public class UserController {
public UserDto register(UserDto user) {
switch(user.getTypeOfUser()) {
case DRIVER: return driverService.register(user);
case CUSTOMER: return customerService.register(user);
// ...
}
}
public UserDto update(UserDto user) {
switch(user.getTypeOfUser) {
case DRIVER: return driverService.update((DriverDto) user);
case CUSTOMER: return customerService.update((CustomerDto) user);
// ...
}
}
public UserDto login(long userId) {
loginService.login(userId);
UserBO user = userService.readById(userId);
switch(user.getTypeOfUser) {
case DRIVER: return DriverDto.fromBO((DriverBO) user);
case CUSTOMER: return CustomerDto.fromBO((CustomerBO) user);
// ...
}
}
// ...
}
I understand that something like Visitor pattern could be used, but would I really need to add the methods of registration / login /update / delete in the Enum itself? I don't really have a clear idea on how to do that, any help is appreciated.
I'd like to replace that with some better design.
The first step towards replacing the switch statement and take advantage of Polymorphism instead is to ensure that there is a single contract (read method signature) for each of the operations regardless of the user type. The following steps will explain how to achieve this :
Step 1 : Define a common interface for performing all operations
interface UserService {
public UserDto register(UserDto user);
public UserDto update(UserDto user);
public UserDto login(UserDto user)
}
Step 2 : Make UserController take a UserService as a dependency
public class UserController {
private UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
public UserDto register(UserDto user) {
userService.register(user);
}
public UserDto update(UserDto user) {
userService.update(user);
}
public UserDto login(long userId) {
userService.login(user);
}
}
Step 3 : Create subclasses to handle different types of users that take CustomerDto and CustomerBO as a dependency
class CustomerService implements UserService {
private CustomerDto userDto;
private CustomerBO userBO;
public CustomerService(UserDto userDto,UserBO userBo) {
this.userDto = (CustomerDto)userDto;
this.userBO= (CustomerBO)userBo;
}
//implement register,login and update methods to operate on userDto and userBo
}
Implement the DriverService class in a similar fashion with a dependency on DriverBo and DriverDto objects respectively.
Step 4 : Implement a runtime factory that decides which service to pass to UserController :
public UserControllerFactory {
public static void createUserController(UserDto user) {
if(user.getTypeOfUser().equals(CUSTOMER)) {
return new UserController(new CustomerService(user));
} else if(user.getTypeOfUser().equals(DRIVER)) {
return new UserController(new DriverService(user));
}
}
}
Step 5 Call the factory to create a user controller
UserDto user = someMethodThatCreatesUserDto(();
UserController controller = UserControllerFactory.createUserController(user);
controller.register();
controller.update();
controller.login();
The advantage of the above approach is that the switch/if-else statements are moved all they way back to a single class i.e the factory.
You'd want something like that:
public abstract class User {
abstract void register();
abstract void update();
abstract void login();
// maybe some more common non-abstract methods
}
Any type of User will have a class that extends this abstract class and therefore must implement all its abstract methods, like this:
public class Driver extends User {
public void register() {
// do whatever a driver does when register...
}
public void update() {
// do whatever a driver does when update...
}
public void login() {
// do whatever a driver does when login...
}
}
public class Customer extends User {
public void register() {
// do whatever a customer does when register...
}
public void update() {
// do whatever a customer does when update...
}
public void login() {
// do whatever a customer does when login...
}
}
This way, you're avoiding any switch case code. For instance, you can have an array of Users, each one them will be instantiated using new Driver() or new Customer(). Then, for example, if you're iterating over this array and executing all the Users login() method, each user's login() will be called according to its specific type ==> no switch-case needed, no casting needed!
Very simple example (only for different login logic for DriverDto and CustomerDto) - I've resigned from field typeOfUser (because it is not necessary in my solution) - I'm not sure that this is possible in your solution:
public abstract class UserDto {
// put some generic data & methods here
}
public class CustomerDto extends UserDto {
private String customerName;
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
}
public class DriverDto extends UserDto {
private String driverName;
public String getDriverName() {
return driverName;
}
public void setDriverName(String driverName) {
this.driverName = driverName;
}
}
public class ThisIsServiceOrDelegateToOtherServices {
public void login(CustomerDto customer) {
String name = customer.getCustomerName();
System.out.println(name);
// work on name here
}
public void login(DriverDto customer) {
String name = customer.getDriverName();
System.out.println(name);
// work on name here
}
}
Usage:
public static void main(String... args) {
//demo data
CustomerDto customer = new CustomerDto();
customer.setCustomerName("customerName");
DriverDto driver = new DriverDto();
driver.setDriverName("driverName");
// usage
ThisIsServiceOrDelegateToOtherServices service = new ThisIsServiceOrDelegateToOtherServices();
service.login(customer);
service.login(driver);
}
If you really need that TypeOfUser-enum in your UserDTO, then you could extend your enum with a serivce. So you create a TypeOfUserService interface. CustomerSerivce and DriverService will inherit from that service:
public interface TypeOfUserService {
public void register(UserDTO user);
// ...
}
public class CustomerService implements TypeOfUserService {
#Override
public void register(UserDTO user) {
// ...
}
}
public class DriverService implements TypeOfUserService {
#Override
public void register(UserDTO user) {
// ...
}
}
Then you create your register, update, etc. methods in your TypeOfUser enum:
public enum TypeOfUser {
DRIVER(new DriverService()),
CUSTOMER(new CustomerService());
private TypeOfUserService typeOfUserService;
TypeOfUser(TypeOfUserService typeOfUserService) {
this.typeOfUserService = typeOfUserService;
}
public static void register(String typeOfUser, UserDTO user) {
TypeOfUser.valueOf(typeOfUser).typeOfUserService.register(user);
}
// ...
}
You could then call the register method via:
class UserController() {
public UserDto register(UserDto user) {
TypeOfUser.register(user.getTypeOfUser, user);
}
}

Spring: How to get bean implementation dynamically?

Let's say we have interface:
public interface IAuthentication { }
and two implementations:
public class LdapAuthentication implements IAuthentication {}
public class DbAuthentication implements IAuthentication {}
And finally we have a bean that is responsible for processing authentication. This bean should use one of the implementations shown above (based on configuration specified in for example db).
#Service
public class AuthenticationService {
public boolean authenticate(...) {
boolean useDb = ...; //got from db
//my problem here
//how to get right implementation: either LdapAuthentication or DbAuthentication?
IAuthentication auth = ...;
return auth.authenticate(...);
}
}
Question:
How to get the right implementation?
If parameter value does not change:
#Service
public class AuthenticationService {
private IAuthentication auth;
#PostConstruct
protected void init() {
boolean useDb = ...; //got from db
this.auth = ...; //choose correct one
}
public boolean authenticate(...) {
return auth.authenticate(...);
}
}
If parameter is dynamic
#Service
public class AuthenticationService {
#Autowired
private ApplicationContext сontext;
public boolean authenticate(...) {
boolean useDb = ...; //got from db
IAuthentication auth = context.getBean(useDb ? DbAuthentication.class : LdapAuthentication.class);
return auth.authenticate(...);
}
}

Hystrix: HystrixBadRequestException for failed validations

I am trying to understand how Hystrix works with non-fault errors and the HystrixBadRequestException, particularly in the area of validation. I use JSR-303 bean validation (Hibernate validator) for all my beans:
public class User {
#Min(1L)
private Long id;
#NotNull
#Email
private String email;
}
public class UserValidator {
private Validator validator;
// Throw exception if the user is invalid; return void otherwise.
public void validateUser(User user) {
Set<ConstraintViolation<User>> violations = validator.validate(user);
if(!violations.isEmpty()) {
return new BadEntityException(violations);
}
}
}
// Hystrix command.
public class SaveUserCommand extends HystrixCommand<User> {
public User user;
public void doSaveUser(User user) {
this.user = user;
execute();
}
#Override
protected User run() {
// Save 'user' somehow
}
#Override
protected User getFallback() {
return null;
}
}
// My service client that uses my Hystrix command.
public class UserClient {
private SaveUserCommandFactory factory = new SaveUserCommandFactory();
private UserValidator validator = new UserValidator();
public User saveUser(User user) {
SaveUserCommand saveUserCommand = factory.newSaveUserCommand();
validator.validate(user);
user = saveUserCommand.doSaveUser(user);
return user;
}
}
While this should work, I feel like the HystrixBadRequestException was created for this purpose, and I could somehow be putting the validator inside the command (not outside of it). According to the docs, this exception was intended for non-fault exceptions, including illegal arguments. I'm just not seeing how I could put my validation inside the command and leverage it (such that failed validations don't count against my metrics/stats).
It turns out you need to throw the HystrixBadRequestException inside the HystrixCommand impl. In my case, the solution was to move the validator into the SaveUserCommand#run() method:
#Override
protected void run() {
try {
validator.validate(user);
// Save user somehow
} catch(BadEntityException bexc) {
log.error(bexc);
throw new HystrixBadRequestException("Hystrix caught a bad request.", bexc);
}
}
Now, if validation fails, the outer exception is a HystrixBadRequestException and it will not count against circuit breaker stats or published metrics.

Categories