Spring Amqp - Dynamically Disable/Enable RabbitListener while DB Batch running - spring-amqp

We have the scenario where messages are pulled off of an Amqp Queue and written to our DB - However, during scheduled DB batch runs the DB is unavailable and we're unable to write and so we would like messages to remain on the queue during these windows.
I'm trying to ascertain the best way to deal with this - simply throw an exception in the #RabbitListener method to (repeatedly) re-queue the messages or using a Spring scheduler attempt to stop/start the listener (I see that the SimpleMessageListenerContainer has stop/start methods).
Any suggestions as to the best (or better) approaches?

Another way to take into account is a reply capabilities on the listener.
See an AbstractRabbitListenerContainerFactory JavaDocs:
/**
* Set a {#link RetryTemplate} to use when sending replies; added to each message
* listener adapter.
* #param retryTemplate the template.
* #since 2.0.6
* #see #setReplyRecoveryCallback(RecoveryCallback)
* #see AbstractAdaptableMessageListener#setRetryTemplate(RetryTemplate)
*/
public void setRetryTemplate(RetryTemplate retryTemplate) {
this.retryTemplate = retryTemplate;
}
/**
* Set a {#link RecoveryCallback} to invoke when retries are exhausted. Added to each
* message listener adapter. Only used if a {#link #setRetryTemplate(RetryTemplate)
* retryTemplate} is provided.
* #param recoveryCallback the recovery callback.
* #since 2.0.6
* #see #setRetryTemplate(RetryTemplate)
* #see AbstractAdaptableMessageListener#setRecoveryCallback(RecoveryCallback)
*/
public void setReplyRecoveryCallback(RecoveryCallback<?> recoveryCallback) {
this.recoveryCallback = recoveryCallback;
}
And you are right: you can use start()/stop() as well.
For this reason you need to get injected a RabbitListenerEndpointRegistry bean and use its:
/**
* Return the {#link MessageListenerContainer} with the specified id or
* {#code null} if no such container exists.
* #param id the id of the container
* #return the container or {#code null} if no container with that id exists
* #see RabbitListenerEndpoint#getId()
* #see #getListenerContainerIds()
*/
public MessageListenerContainer getListenerContainer(String id) {
To get access to an appropriate listener container for your #RabbitListener and stop() or start() it according your logic.

Related

Using spring-authorization-server, how do you retrieve the context/request from an in-progress authentication outside of the auth server framework?

The use case I am trying to solve for is to be able to display some details about the registered client associated with an OAuth request when a user must log in via a form. For example, it would be great to be able to display a friendly name for a client. I can handle mapping this kind of data once I have a client ID, but I am unsure about how to retrieve the client ID (or other identifying information) about the originating request elsewhere in the Spring Boot application.
I looked through the codebase for anything similar to a holder (such as the Spring Security SecurityContextHolder) or anything that stored data in session, but I could not find any references. This data must be persisted somehow between the original request through the login process. How do I retrieve it?
Thanks!
It looks like this is handled outside of the framework via a SavedRequest in the session. If you're faced with a similar problem, this is how I'm fetching the OAuth2 client on the login page from a controller.
/**
* Retrieves a friendly OAuth2 client name for the given login request.
* <p>
* In order for this to work, a couple of conditions must be met:
*
* <ol>
* <li>The original request must have been a valid OAuth2 request.</li>
* <li>The client must be configured with a friendly name.</li>
* </ol>
* <p>
* If a client name can not be found, {#code null} is returned.
*
* #param session HTTP session of the request.
* #return The friendly client name, or {#code null}.
*/
private String getClientName(HttpSession session) {
if (session != null) {
DefaultSavedRequest savedRequest = (DefaultSavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST");
if (savedRequest != null && savedRequest.getParameterMap().containsKey("client_id")) {
String[] values = savedRequest.getParameterMap().get("client_id");
if (values.length > 0) {
String clientId = values[0];
RegisteredClient registeredClient = registeredClientRepository.findByClientId(clientId);
if (registeredClient != null && StringUtils.hasLength(registeredClient.getClientName())) {
return registeredClient.getClientName();
}
}
}
}
return null;
}

OAuth2ClientAuthenticationProcessingFilter get token

How can I get token from backend java server
I have a oauth server authentication and I can login successfully with Spring security layer. I get toke in web browser client via http get request...
https://x.x.x.x/oxauth/restv1/token
How can I get token in backend part using OAuth2ClientAuthenticationProcessingFilter class?
/**
* Called after executed Configuration "addFilterBefore"
*
* #return OAuth2ClientAuthenticationProcessingFilter
*/
private OAuth2ClientAuthenticationProcessingFilter oauthFilter() {
OAuth2ClientAuthenticationProcessingFilter oauthFilter = new OAuth2ClientAuthenticationProcessingFilter("/login");
// OAuth2RestTemplate > Spring Boot does not automatically create such a bean,
OAuth2RestTemplate oauthTemplate = new OAuth2RestTemplate(oauth(), oauth2ClientContext);
UserInfoTokenServices tokenServices = new UserInfoTokenServices(oauthResource().getUserInfoUri(), oauth().getClientId());
tokenServices.setRestTemplate(oauthTemplate);
oauthFilter.setRestTemplate(oauthTemplate);
oauthFilter.setTokenServices(tokenServices);
return oauthFilter;
}
I found a way to do that... oauthApplication.getOauth2ClientContext().getAccessToken()

Error on custom middleware checking the value returned on a Model custom Function Laravel 5.1

I have an account email confirmation for my Laravel app, then I want to check when the user tries to log in, if the user has activated his account.
I found this: https://laracasts.com/discuss/channels/general-discussion/how-to-test-if-a-user-which-tries-to-log-in-is-confirmed-yet
I have a custom model function isActivated that only return the state attibute(boolean type, named estado in spanish) on user model.
On my User Model:
public function isActivated()
{
return $this->estado;
}
I created my middleware similar as the link above provided advices, then I registered in App/Http/Kernel.php as a middleware route
The problem comes when I assign my middleware to my route (instead of create the construct function in my controller, I want this middleware just on post request of the login controller).
When I tried to log in throws an error:
Fatal Throwable Error:
Fatal Error: Call to a member function isActivated() on null
My middleware looks exacts as the link
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class RedirectIfNotMailActivated
{
/**
* The Guard implementation.
*
* #var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* #param Guard $auth
* #return void
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ( ! $this->auth->user()->isActivated()) {
return redirect('/login')
->with('mensaje',
'¡Lo sentimos, no ha confirmado su cuenta aún!');
} else {
return $next($request);
}
}
}
The fun part: if I add the content of the handle function of my middleware in the App/Http/Middleware/Authenticate(auth middleware) and then I group and attach some routes to this middleware, this works as expected (not allowing non confirmed users to login)
The problem is that I have a polimorphic relationship in users table for user type (Admin and Customer) so I attached and grouped the admins control panel to auth middleware because I need to restict the access to control panel just for authenticated users and admin type(not allowed for customer user type).
Restriction only takes part on Admin User type.
And of coursethis let the Customer user types can login because I have nothing that restict the if his account is confirmed or not.
What am I doing wrong... The isActivated model function work ok when added in auth middleware, but no when I use this same approach in my custom middleware.
Thanks....
EDITED
My middleware asigned to my post method for my login controller
Route::post('/login', [
'middleware' => 'activated.email',
'uses' => 'loginController#store'
]);
PD: sorry for long post and bad english habilities, it is not my first language :(
You have a problem with our logic. Your login path should not be protected with am activated user, because middleware is executed before the request, so the user can't event attempt to login in your case and you get an error because of that.
What you can do instead is add your isActivated() check in the Authenticate middleware, so there you'll have a logged user and $this->auth->user() won't be null.

how to stop Spring AMQP annotated message listener from receiving messages

when my Spring AMQP message listener recognizes an error, I want to stop receiving messages from the queue. When I have a ListenerContainer configured as bean, I can call stop() on it.
Can I do something similar, when I have configured my listener with an endpoint annotation? E.g. is it possible to inject the ListenerContainer the container has created for me?
thx,
tchick
Please, find #RabbitListener#id() JavaDocs:
/**
* The unique identifier of the container managing for this endpoint.
* <p>If none is specified an auto-generated one is provided.
* #return the {#code id} for the container managing for this endpoint.
* #see org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry#getListenerContainer(String)
*/
String id() default "";
So, you have to inject to your target service the RabbitListenerEndpointRegistry and use it to get access to desired ListenerContainer by its id.

Alfresco SDK code hanging at AuthenticationUtils.startSession

i am testing the code from SDK to call Alfresco on bitNami Alresco 4.0.e-0 server with a webapp that is located on same tomcat server as Alfresco. The code hangs at the very first call to AuthenticationUtils to get session. I pretty am sure i supplied the standard bitNami Alfresco user and password for this. Did i miss any libraries? I put most available dependencies as my local maven repositories and code compiles well.
the following is code from SDK without Alfresco license as i could not format the code with it:
package org.alfresco.sample.webservice;
import org.alfresco.webservice.repository.RepositoryServiceSoapBindingStub;
import org.alfresco.webservice.types.Store;
import org.alfresco.webservice.util.AuthenticationUtils;
import org.alfresco.webservice.util.WebServiceFactory;
public class GetStores extends SamplesBase
{
/**
* Connect to the respository and print out the names of the available
*
* #param args
*/
public static void main(String[] args)
throws Exception
{
// Start the session
AuthenticationUtils.startSession(USERNAME, PASSWORD);
try
{
// Get the respoitory service
RepositoryServiceSoapBindingStub repositoryService = WebServiceFactory.getRepositoryService();
// Get array of stores available in the repository
Store[] stores = repositoryService.getStores();
if (stores == null)
{
// NOTE: empty array are returned as a null object, this is a issue with the generated web service code.
System.out.println("There are no stores avilable in the repository.");
}
else
{
// Output the names of all the stores available in the repository
System.out.println("The following stores are available in the repository:");
for (Store store : stores)
{
System.out.println(store.getScheme() + "://" + store.getAddress());
}
}
}
finally
{
// End the session
AuthenticationUtils.endSession();
}
}
}
The WebServiceFactory uses
http://localhost:8080/alfresco/api
as default endpoint.You can change the endpoint by providing a file called webserviceclient.properties on the classpath under alfresco (the resource path: alfresco/webserviceclient.properties)
The properties file must offer a property called repository.location, which specifies the endpoint URL. Since you are using a bitnami Alfresco instance, it is probably running on port 80. The file should contain the following property entry:
repository.location=http://localhost:80/alfresco/api

Resources