In previous versions of Spring + Spring security, when I didnt use the built in CSFR, it was easy to add session conversation support (for supporting multiple "edit" tabs), using the techniques described at https://github.com/duckranger/Spring-MVC-conversation, specifically implementing a RequestDataValueProcessor
however, now that we use spring boot and all it's auto configure goodness, CsrfRequestDataValueProcessor now implements RequestDataValueProcessor
if I add my own RequestDataValueProcessor implemenation, it never gets used.
Can anyone point me in the right direction so that I can use both CsrfRequestDataValueProcessor and my RequestDataValueProcessor
I assume I would need to create a composite RequestDataValueProcessor, or can you have multiple RequestDataValueProcessor implemenations?
Thanks in advance
I just solved this very problem by a small modification to the duckranger solution. I wedged a call to a ScrfRequestDataValueProcessor into the getExtraHiddenFields method.
#Override
public Map<String, String> getExtraHiddenFields(HttpServletRequest request) {
CsrfRequestDataValueProcessor csrfRDVP = new CsrfRequestDataValueProcessor();
Map<String, String> hiddenFields = csrfRDVP.getExtraHiddenFields(request);
if (request.getAttribute(ConversationalSessionAttributeStore.CID_FIELD) != null) {
hiddenFields.put(ConversationalSessionAttributeStore.CID_FIELD,
request.getAttribute(ConversationalSessionAttributeStore.CID_FIELD).toString());
}
return hiddenFields;
}
Just implemented this today and have barely started user testing so USE AT YOUR OWN RISK.
I can't help but think there's a better way but this seems to do the trick.
Thought I would share what I did to get this working.
I needed a solution, and I just couldn't get my own RequestDataValueProcessor to be used by Thymeleaf, even though the bean was created in my configuration correctly.
Note: I am aware that this is quite a hack, but it is pretty interesting at the same time.
The Solution: AspectJ.....
#Aspect
public class SessionConversationAspect {
private final ConversationIdRequestProcessor conversationIdRequestProcessor;
public SessionConversationAspect() {
this.conversationIdRequestProcessor = new ConversationIdRequestProcessor();
}
#Pointcut("execution(* org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor.getExtraHiddenFields(..) ) && args(request) )")
protected void getExtraHiddenFields(HttpServletRequest request) {
}
#AfterReturning(
pointcut = "getExtraHiddenFields(request)",
returning = "hiddenFields"
)
protected void addExtraHiddenFields(HttpServletRequest request, Map<String, String> hiddenFields) {
Map<String, String> extraFields = conversationIdRequestProcessor.getExtraHiddenFields(request);
hiddenFields.putAll(extraFields);
}
}
Related
I am trying to implement non blocking retries with single topic fixed back-off.
I am able to do so, thanks to documentation https://docs.spring.io/spring-kafka/reference/html/#single-topic-fixed-delay-retries.
Now I also need to perform a few blocked/local retries on main topic. I have been trying to implement this using DefaultErrorHandler as below:
#Bean
public DefaultErrorHandler retryErrorHandler() {
return new DefaultErrorHandler(new FixedBackOff(2000, 3));
}
This does not seem to work with RetryableTopic.
I have also tried the following approach retry-topic-combine-blocking https://docs.spring.io/spring-kafka/reference/html/#retry-topic-combine-blocking using ListenerContainerFactoryConfigurer
but issue I am facing here is creating beans KafkaConsumerBackoffManager, DeadLetterPublishingRecovererFactory and especially KafkaConsumerBackoffManager.
I need to know if this another way to achieve this using spring kafka framework or is there a way to construct above beans ?
We're currently working on improving configuration for the non-blocking retries components.
For now, as documented here, you should inject these beans such as:
#Bean(name = RetryTopicInternalBeanNames.LISTENER_CONTAINER_FACTORY_CONFIGURER_NAME)
public ListenerContainerFactoryConfigurer lcfc(KafkaConsumerBackoffManager kafkaConsumerBackoffManager,
DeadLetterPublishingRecovererFactory deadLetterPublishingRecovererFactory,
#Qualifier(RetryTopicInternalBeanNames
.INTERNAL_BACKOFF_CLOCK_BEAN_NAME) Clock clock) {
ListenerContainerFactoryConfigurer lcfc = new ListenerContainerFactoryConfigurer(kafkaConsumerBackoffManager, deadLetterPublishingRecovererFactory, clock);
lcfc.setBlockingRetryableExceptions(MyBlockingRetryException.class, MyOtherBlockingRetryException.class);
lcfc.setBlockingRetriesBackOff(new FixedBackOff(500, 5)); // Optional
return lcfc;
}}
Also, there's a known issue where if you try to inject the beans before the first #KafkaListener bean with retryable topic is processed, the feature's component's beans won't be present in the context yet and will throw an error.
Does that happen to you?
We're currently working on a fix for this, but we should be able to work around that if that's your problem.
EDIT: Since the problem is that components are not instantiated yet, the most guaranteed workaround is to provide the components yourself.
Here's a sample on how to do that. Of course, adjust it accordingly if you need any further customization.
#Configuration
public static class SO71705876Configuration {
#Bean(name = RetryTopicInternalBeanNames.LISTENER_CONTAINER_FACTORY_CONFIGURER_NAME)
public ListenerContainerFactoryConfigurer lcfc(KafkaConsumerBackoffManager kafkaConsumerBackoffManager,
DeadLetterPublishingRecovererFactory deadLetterPublishingRecovererFactory) {
ListenerContainerFactoryConfigurer lcfc = new ListenerContainerFactoryConfigurer(kafkaConsumerBackoffManager, deadLetterPublishingRecovererFactory, Clock.systemUTC());
lcfc.setBlockingRetryableExceptions(IllegalArgumentException.class, IllegalStateException.class);
lcfc.setBlockingRetriesBackOff(new FixedBackOff(500, 5)); // Optional
return lcfc;
}
#Bean(name = RetryTopicInternalBeanNames.KAFKA_CONSUMER_BACKOFF_MANAGER)
public KafkaConsumerBackoffManager backOffManager(ApplicationContext context) {
PartitionPausingBackOffManagerFactory managerFactory =
new PartitionPausingBackOffManagerFactory();
managerFactory.setApplicationContext(context);
return managerFactory.create();
}
#Bean(name = RetryTopicInternalBeanNames.DEAD_LETTER_PUBLISHING_RECOVERER_FACTORY_BEAN_NAME)
public DeadLetterPublishingRecovererFactory dlprFactory(DestinationTopicResolver resolver) {
return new DeadLetterPublishingRecovererFactory(resolver);
}
#Bean(name = RetryTopicInternalBeanNames.DESTINATION_TOPIC_CONTAINER_NAME)
public DestinationTopicResolver destinationTopicResolver(ApplicationContext context) {
return new DefaultDestinationTopicResolver(Clock.systemUTC(), context);
}
In the next release this should not be a problem anymore. Please let me know if that works for you, or if any further adjustment to this workaround is necessary.
Thanks.
New to WebFlux, reactive, and handlers.
I am able to get a Mono<> from a ServerRequest and process the contained POJO to add a new tuple to a database. But, it seems like there should be a "better" or "more accepted" way to write this code.
Any help/input with the code in AccountRequestHandler would be appreciated, especially with explanations of the rationale behind the recommend change(s).
Router implementation (stripped down to only "POST")...
#Configuration
public class AccountRequestRouter {
#Bean
public RouterFunction<ServerResponse> route(AccountRequestHandler requestHandler) {
return nest(path("/v2"),
nest(accept(APPLICATION_JSON),
.andRoute(RequestPredicates.POST("/accounts"), requestHandler::addAccount)
));
}
}
Handler implementation...
The code where I'm actually doing the add, and then separately creating a ServerResponse, is what I'm focused on. It seems "clunky", especially since AccountService.addAccount() returns a Mono on completion.
#Component
public class AccountRequestHandler {
#Autowired
private mil.navy.ccop.service.accounts.account.AccountService accountService;
public Mono<ServerResponse> addAccount(ServerRequest request) {
return request.bodyToMono(Account.class).flatMap(account -> {
accountService.addAccount(account);
return ServerResponse.ok().build();
})
.switchIfEmpty(ServerResponse.badRequest()
.contentType(APPLICATION_JSON)
.build(Mono.empty()));
}
}
AccountService implementation (again, stripped down)...
#Service
class AccountService {
#Autowired
private AccountRepository accounts;
public AccountService() {
}
public Mono<Void> addAccount(Account account) {
Account proxy;
// make sure that accountId is set to support auto-generation of synthetic key value
proxy = new Account(-1, account.getShortName(), account.getLongName(), account.getDescription());
accounts.save(proxy);
return Mono.empty();
}
}
Appreciating all the help in ramping up on this style of programming....
well first of all, you have 2 addAccount, that can be a bit confusing.
Second of all, what kind of "repository" are you writing too? if its an sql repo you need to properly wrap it in a Mono.fromCallable() otherwise it will block the Reactive thread pool and you can have really bad performance.
Yes there are other ways of doing things. A lot of people tend to do things in flatmap or map and sure it is completely possible to do things here, but for the semantics i'd say it is less good.
map and flatmap are usually used to perform some sort of computation on the inner value of the mono and then return the same or a new value and or type inside the mono.
i would rewrite this like such.
return void here:
public void addAccount(Account account) {
Account proxy;
// make sure that accountId is set to support auto-generation of synthetic key value
proxy = new Account(-1, account.getShortName(), account.getLongName(), account.getDescription());
accounts.save(proxy);
}
And here:
public Mono<ServerResponse> addAccount(ServerRequest request) {
return request.bodyToMono(Account.class)
.doOnSuccess(account -> {
accountService.addAccount(account);
}).then(ServerResponse.ok().build())
.switchIfEmpty(ServerResponse.badRequest()
.contentType(APPLICATION_JSON)
.build());
}
there are a number of different doOn methods that are ment to be used to consume and do "side effects" on things. Like doOnSuccess, doOnError, doOnCancel etc. etc.
you also have then and thenReturn which will just return whatever you put in them. Then returns whatever Mono you put in it. thenReturn wraps whatever value you put into it into a Mono and returns it.
When using spring-data-rest there is a post processing of Resource classes returned from Controllers (e.g. RepositoryRestControllers). The proper ResourceProcessor is called in the post processing.
The class responsible for this is ResourceProcessorHandlerMethodReturnValueHandler which is part of spring-hateoas.
I now have a project that only uses spring-hateoas and I wonder how to configure ResourceProcessorHandlerMethodReturnValueHandler in such a scenario. It looks like the auto configuration part of it still resides in spring-data-rest.
Any hints on how to enable ResourceProcessorHandlerMethodReturnValueHandler in a spring-hateoas context?
I've been looking at this recently too, and documentation on how to achieve this is non-existent. If you create a bean of type ResourceProcessorInvokingHandlerAdapter, you seem to lose the the auto-configured RequestMappingHandlerAdapter and all its features. As such, I wanted to avoid using this bean or losing the WebMvcAutoConfiguration, since all I really wanted was the ResourceProcessorHandlerMethodReturnValueHandler.
You can't just add a ResourceProcessorHandlerMethodReturnValueHandler via WebMvcConfigurer.addReturnValueHandlers, because what we need to do is actually override the entire list, as is what happens in ResourceProcessorInvokingHandlerAdapter.afterPropertiesSet:
#Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
// Retrieve actual handlers to use as delegate
HandlerMethodReturnValueHandlerComposite oldHandlers = getReturnValueHandlersComposite();
// Set up ResourceProcessingHandlerMethodResolver to delegate to originally configured ones
List<HandlerMethodReturnValueHandler> newHandlers = new ArrayList<HandlerMethodReturnValueHandler>();
newHandlers.add(new ResourceProcessorHandlerMethodReturnValueHandler(oldHandlers, invoker));
// Configure the new handler to be used
this.setReturnValueHandlers(newHandlers);
}
So, without a better solution available, I added a BeanPostProcessor to handle setting the List of handlers on an existing RequestMappingHandlerAdapter:
#Component
#RequiredArgsConstructor
#ConditionalOnBean(ResourceProcessor.class)
public class ResourceProcessorHandlerMethodReturnValueHandlerConfigurer implements BeanPostProcessor {
private final Collection<ResourceProcessor<?>> resourceProcessors;
#Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof RequestMappingHandlerAdapter) {
RequestMappingHandlerAdapter requestMappingHandlerAdapter = (RequestMappingHandlerAdapter) bean;
List<HandlerMethodReturnValueHandler> handlers =
requestMappingHandlerAdapter.getReturnValueHandlers();
HandlerMethodReturnValueHandlerComposite delegate =
handlers instanceof HandlerMethodReturnValueHandlerComposite ?
(HandlerMethodReturnValueHandlerComposite) handlers :
new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
requestMappingHandlerAdapter.setReturnValueHandlers(Arrays.asList(
new ResourceProcessorHandlerMethodReturnValueHandler(delegate,
new ResourceProcessorInvoker(resourceProcessors))));
return requestMappingHandlerAdapter;
}
else return bean;
}
}
This has seemed to work so far...
So if I have:
public class CustomerViewModel
{
public CustomerViewModel(ICustomer customer)
{
this.customer = customer
}
}
then is there a way to achieve:
ICustomerViewModel customerViewModel = container.Resolve<ICustomerViewModel>(existingCustomer);
If you want to build-up an existing instance through property and method injection, you can use the following:
var model = new CustomerViewModel(customer);
model = container.BuildUp(model);
In general I would not recommend using this feature of Unity. Sometimes you need it, but it's usually a warning sign that could be fixed by adjusting the design a bit to work more naturally with IoC as a pattern (not a framework). With more details on how you are using it, the SO community can probably offer some other options...
Since the dependency injection container is designed to provide finished objects, you'll need to use a factory pattern (which is quite common in these cases) to achieve your desired configuration:
public interface ICustomerViewModelFactory {
public ICustomerViewModel GetModelFor(ICustomer customer);
}
public class CustomerViewModelFactory : ICustomerViewModelFactory {
public ICustomerViewModel GetModelFor(ICustomer customer) {
return new CustomerViewModel(customer);
}
}
// elsewhere...
container.RegisterInstance<ICustomerViewModelFactory>(new CustomerViewModelFactory());
// and finally...
ICustomerViewModelFactory factory = container.Resolve<ICustomerViewModelFactory>();
ICustomerViewModel customerViewModel = factory.GetModelFor(existingCustomer);
Check the 'Can I pass constructor parameters to Unity's Resolve() method?' question (also on Stack Overflow).
Basically I'm trying to create a SessionManager class which I can use to manage sessions in my MVC applications. For that I'm thinking the best way of doing so is by creating a wrapper class for HttpContext which would then allow me to access HttpContext.Current.Session.
To be honest, I'm not really sure about the whole thing, I just feel it's the logical way of doing so. I also want to create an ISessionManager and ISession interfaces, and then implement them according to my application's needs. For my current project, and for now, I need a InProc session management, but I might need to store session data in MSSQL Server when we decide to expand and use a web farm or a garden. That's why I'm trying to build a sort of an extensible framework right from the start.
Final note, I will be using Microsoft Unity to inject the concrete SessionManager of choice. I believe that's a good way to maintain a certain level of abstraction.
Any suggestions for achieving all that?
Thanks in advance! :)
Ok here's what I came up with, but I'm not sure that's the right way of doing this so your opinions are most welcome!
ISessionManager:
public interface ISessionManager
{
void RegisterSession(string key, object obj);
void FreeSession(string key);
}
SessionManager:
public class SessionManager : ISessionManager
{
private IDictionary<string, object> sessionDictionary;
public SessionManager(IDictionary<string, object> _sessionDictionary)
{
sessionDictionary = _sessionDictionary;
}
public IDictionary<string, object> Session
{
get
{
return sessionDictionary;
}
}
public void RegisterSession(string key, object obj)
{
sessionDictionary[key] = obj;
}
public void FreeSession(string key)
{
sessionDictionary[key] = null;
}
}
Then when I want to instantiate the class (inside my web app), I would do something like that:
var sessionManager = new SessionManager(HttpContext.Current.Session);
sessionManager.RegisterSession["myKey"] = someObject;
But I would prefer to avoid using magic strings as the key. I could include a constant string property like sessionKey = "myKey" in the class, but that would mean I could only store one object in the session manager, right?
Feedback please. :)