Grails, Can not make spring-security event notification to work - events

I try to log logins and logouts using the event handling of spring-security but nothing happens.
I enabled event handling in Aplication.groovy:
grails.plugin.springsecurity.useSecurityEventListener = true
and registered the bean in resources.groovy:
import grails.databinding.converters.ValueConverter
import com.torntrading.utils.DatabaseMessageSource
import org.springframework.web.servlet.i18n.SessionLocaleResolver
import com.myproj.AuthenticationSuccessEventListener
beans = {
authenticationSuccessEventListener(AuthenticationSuccessEventListener)
}
And the event class in folder "Utility Classes":
package com.myproj
import org.springframework.context.ApplicationListener
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent
/**
*
* #author Lars
*/
class AuthenticationSuccessEventListener implements
ApplicationListener<InteractiveAuthenticationSuccessEvent> {
#Override
public void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) {
println(springSecurityService.getPrincipal().username + "***** LOGGED IN ! ******" + new Date())
}
}
The text is never printed so I assume that the event is not fired.
What's wrong with my code?
Using version: spring-security-core:3.1.1'

Related

Invalid Address JMSException when using temporary credentials with SQSSession

I am getting an error trying to connect to an SQS queue in another AWS account using JMS. I have tried to follow the approach taken in this answer, but I am receiving the following error:
com.amazonaws.services.sqs.model.AmazonSQSException: The address https://sqs.us-east-1.amazonaws.com/ is not valid for this endpoint. (Service: AmazonSQS; Status Code: 404; Error Code: InvalidAddress; Request ID: d7f72bd3-6240-5f63-b313-70c2d8978c14; Proxy: null)
Unlike in the post mentioned above (which I believe has the account credentials in the default provider chain?) I am trying to assume a role that has access to this SQS queue. Is this not possible through JMS or am I doing something incorrectly?
import com.amazon.sqs.javamessaging.ProviderConfiguration;
import com.amazon.sqs.javamessaging.SQSConnectionFactory;
import com.amazon.sqs.javamessaging.SQSSession;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.securitytoken.AWSSecurityTokenService;
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.support.destination.DynamicDestinationResolver;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.Session;
/**
* A configuration class for JMS to poll an SQS queue
* in another AWS account
*/
#Configuration
public class TranslationJmsConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(TranslationJmsConfig.class);
#Value("${iam.connection.arn}")
private String connectionRoleArn;
#Value("${account.id}")
private String brokerAccountId;
/**
* JmsListenerContainerFactory bean for translation processing response queue
*
* #param concurrentConsumers number of concurrent consumers
* #param maxConcurrentConsumers max number of concurrent consumers
* #return An instance of JmsListenerContainerFactory
*/
#Bean("translationJmsListenerContainerFactory")
public DefaultJmsListenerContainerFactory translationJmsListenerContainerFactory(
#Value("#{new Integer('${listener.concurrency}')}") int concurrentConsumers,
#Value("#{new Integer('${listener.max.concurrency}')}") int maxConcurrentConsumers) {
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(getConnectionFactory(connectionRoleArn));
factory.setDestinationResolver(new SqsDynamicDestinationResolver(brokerAccountId));
factory.setSessionTransacted(false); //SQS does not support transaction.
factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE); // Automatic message acknowledgment after successful listener execution; best-effort redelivery in case of a user exception thrown as well as in case of other listener execution interruptions (such as the JVM dying).
factory.setConcurrency(String.format("%d-%d", concurrentConsumers, maxConcurrentConsumers));
return factory;
}
/**
* create custom JMS Template
* #return JmsTemplate
*/
#Bean
public JmsTemplate customJmsTemplate() {
JmsTemplate jmsTemplate = new JmsTemplate(getConnectionFactory(connectionRoleArn));
jmsTemplate.setDestinationResolver(new SqsDynamicDestinationResolver(brokerAccountId));
return jmsTemplate;
}
/**
* A dynamic destination resolver for sqs queue
*/
public class SqsDynamicDestinationResolver extends DynamicDestinationResolver {
private final String brokerAccountId;
/**
* Constructor
* #param brokerAccountId broker Account Id
*/
public SqsDynamicDestinationResolver(String brokerAccountId) {
this.brokerAccountId = brokerAccountId;
}
#Override
protected Queue resolveQueue(Session session, String queueName) throws JMSException {
if (session instanceof SQSSession) {
SQSSession sqsSession = (SQSSession) session;
return sqsSession.createQueue(queueName, brokerAccountId); // 404 invalid address -- Something wrong with creds?
}
return super.resolveQueue(session, queueName);
}
}
private ConnectionFactory getConnectionFactory(String connectionRoleArn){
AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClient.builder()
.build();
// assume the connector account credentials -> so we can assume customer account using chaining
AWSCredentialsProvider dummyCredentialProviders = IdentityHelpers.assumeInternalRole(stsClient, connectionRoleArn); // A helper that assumes temporary creds
return new SQSConnectionFactory(
new ProviderConfiguration(),
AmazonSQSClientBuilder.standard()
.withRegion(Regions.US_EAST_1)
.withCredentials(dummyCredentialProviders)
);
}
}
I realized that when using the temporary credentials, I didn't need the second parameter (the account id) of the sqsSession.createQueue call. so once i changed
sqsSession.createQueue(queueName, brokerAccountId);
To:
return sqsSession.createQueue(queueName);
it worked fine. I guess i missunderstood the need for the account id. I assume the parameter is used when you have multiple accounts in your providerChain and you want it to search a specific account? Any light on this would still be appreciated!

Not able to perform query using vertx-db2-client with Spring Boot and getting error

I'm trying to connect and query to DB2 using vertx-db2-client, but it is not working. I'm using Spring Boot 2.6.6 and vertx-db2-client library to perform query in reactive way. I've created a class which implements CommandLineRunner
Dependency in my build.gradle
implementation 'io.vertx:vertx-db2-client:4.2.6'
implementation 'io.vertx:vertx-reactive-streams:4.2.6'
Below is my CommandLineRunner class.
import io.vertx.db2client.DB2ConnectOptions;
import io.vertx.db2client.DB2Pool;
import io.vertx.sqlclient.PoolOptions;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.RowSet;
import io.vertx.sqlclient.SqlClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;
#Configuration
#Slf4j
public class DB2DataLoader implements CommandLineRunner {
/**
* Callback used to run the bean.
*
* #param args incoming main method arguments
* #throws Exception on error
*/
#Override
public void run(String... args) throws Exception {
DB2ConnectOptions connectOptions =
new DB2ConnectOptions()
.setPort(50001)
.setHost("db_host_name")
.setDatabase("db_name")
.setUser("username")
.setPassword("password");
// Pool options
PoolOptions poolOptions = new PoolOptions().setMaxSize(5);
// Create the client pool
SqlClient client = DB2Pool.client(connectOptions, poolOptions);
// A simple query
client
.query("SELECT * FROM SCHEMA.TABLE")
.execute(
ar -> {
if (ar.succeeded()) {
RowSet<Row> result = ar.result();
System.out.println("Got " + result.size() + " rows ");
} else {
System.out.println("Failure: " + ar.cause().getMessage());
}
// Now close the pool
client.close();
});
}
}
I'm not seeing any connection issues. The error that I see right after the deployment is below:
2022-04-11 15:35:11.740 INFO 2736 --- [ main] c.h.t.p.ServiceApp : Started ServiceApp in 3.746 seconds (JVM running for 4.719)
Failure: SQLState.NET_VCM_VCS_LENGTHS_INVALID: VCM and VCS lengths are mutually exclusive but both were set: vcsLen=255 vcmLen=12336
I'm not sure what is this "Failure: **" means. Can anyone please help me understand this and how to fix. Database connection parameters are correct. I've just masked here. I was following this documentation for the example.

AEM 6.3 : Creating Scheduler using OSGi R6 annotations

I have written a scheduler using OSGi R6 annotations but it doesn't seem to run :
package com.aem.sites.interfaces;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.AttributeType;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
#ObjectClassDefinition(name = "Scheduler Configuration for Weather", description = "Configuration file for Scheduler")
public #interface SchedulerConfiguration {
#AttributeDefinition(
name = "sample parameter",
description="Sample String parameter",
type = AttributeType.STRING
)
public String parameter() default "scheduler";
#AttributeDefinition(
name = "Concurrent",
description = "Schedule task concurrently",
type = AttributeType.BOOLEAN
)
boolean scheduler_concurrent() default true;
#AttributeDefinition(
name = "Expression",
description = "Cron-job expression. Default: run every minute.",
type = AttributeType.STRING
)
String scheduler_expression() default "0 * * * * ?";
}
and
package com.aem.sites.schedulers;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.metatype.annotations.Designate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.aem.sites.interfaces.SchedulerConfiguration;
#Component(immediate = true,
configurationPid = "com.aem.sites.schedulers.WeatherServiceScheduler")
#Designate(ocd=SchedulerConfiguration.class)
public class WeatherServiceScheduler implements Runnable {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private String myParameter;
#Override
public void run() {
logger.info("*******************************************Sample OSGi Scheduler is now running", myParameter);
}
#Activate
public void activate(SchedulerConfiguration config) {
logger.info("*******************************************weather service scheduler"+ myParameter);
myParameter = config.parameter();
}
}
I am following this https://github.com/nateyolles/aem-osgi-annotation-demo/blob/master/core/src/main/java/com/nateyolles/aem/osgiannotationdemo/core/schedulers/SampleOsgiScheduledTask.java but looks like I am doing something wrong here. Not sure what though.
Thanks in advance
In your WeatherSchedulerService class, you are not registering it as a service. Instead of configurationPid, you can do like this service = Runnable.class.
The correct way to create a SlingScheduler using OSGi R6 annotations is as follows -
Create your OSGi configuration class
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.AttributeType;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
#ObjectClassDefinition(name = "Sling Scheduler Configuration", description = "This configuration is used to demonstrates a sling scheduler in action")
public #interface SchedulerConfiguration {
#AttributeDefinition(
name = "Scheduler name",
description = "Name of the scheduler",
type = AttributeType.STRING)
public String name() default "Custom Sling Scheduler";
#AttributeDefinition(
name = "Enabled",
description = "Flag to enable/disable a scheduler",
type = AttributeType.STRING)
public boolean enabled() default false;
#AttributeDefinition(
name = "Cron expression",
description = "Cron expression used by the scheduler",
type = AttributeType.STRING)
public String cronExpression() default "0 * * * * ?";
#AttributeDefinition(
name = "Custom parameter",
description = "Custom parameter to showcase the usage of a sling scheduler",
type = AttributeType.STRING)
public String customParameter();
}
Create your Scheduler class as a service. For creating an OSGi service using R6 annotations we use #Component(service=<your-interface>.class,...).
Thus, create a service as follows
import org.apache.sling.commons.scheduler.ScheduleOptions;
import org.apache.sling.commons.scheduler.Scheduler;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.metatype.annotations.Designate;
import org.redquark.aem.learning.core.configurations.SchedulerConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Component(immediate = true, service = Runnable.class)
#Designate(ocd = SchedulerConfiguration.class)
public class CustomScheduler implements Runnable {
// Logger
private final Logger log = LoggerFactory.getLogger(this.getClass());
// Custom parameter that is to be read from the configuration
private String customParameter;
// Id of the scheduler based on its name
private int schedulerId;
// Scheduler instance injected
#Reference
private Scheduler scheduler;
/**
* Activate method to initialize stuff
*
* #param schedulerConfiguration
*/
#Activate
protected void activate(SchedulerConfiguration schedulerConfiguration) {
schedulerId = schedulerConfiguration.name().hashCode();
customParameter = schedulerConfiguration.customParameter();
}
/**
* Modifies the scheduler id on modification
*
* #param schedulerConfiguration
*/
#Modified
protected void modified(SchedulerConfiguration schedulerConfiguration) {
// Removing scheduler
removeScheduler();
// Updating the scheduler id
schedulerId = schedulerConfiguration.name().hashCode();
// Again adding the scheduler
addScheduler(schedulerConfiguration);
}
/**
* This method deactivates the scheduler and removes it
*
* #param schedulerConfiguration
*/
#Deactivate
protected void deactivate(SchedulerConfiguration schedulerConfiguration) {
// Removing the scheduler
removeScheduler();
}
/**
* This method removes the scheduler
*/
private void removeScheduler() {
log.info("Removing scheduler: {}", schedulerId);
// Unscheduling/removing the scheduler
scheduler.unschedule(String.valueOf(schedulerId));
}
/**
* This method adds the scheduler
*
* #param schedulerConfiguration
*/
private void addScheduler(SchedulerConfiguration schedulerConfiguration) {
// Check if the scheduler is enabled
if (schedulerConfiguration.enabled()) {
// Scheduler option takes the cron expression as a parameter and run accordingly
ScheduleOptions scheduleOptions = scheduler.EXPR(schedulerConfiguration.cronExpression());
// Adding some parameters
scheduleOptions.name(schedulerConfiguration.name());
scheduleOptions.canRunConcurrently(false);
// Scheduling the job
scheduler.schedule(this, scheduleOptions);
log.info("Scheduler added");
} else {
log.info("Scheduler is disabled");
}
}
/**
* Overridden run method to execute Job
*/
#Override
public void run() {
log.info("Custom Scheduler is now running using the passed custom paratmeter, customParameter {}",
customParameter);
}
In the activate() method, we are reading the required values. Then we are getting the schedulerId from the scheduler name.
The modified() method recalculates the schedulerId in case the OSGi configuration is modified.
In the addScheduler() method, we are registering the scheduler using the Scheduler API.
For more information and step by step execution, you can see my blog post as well - Day 13: Schedulers in AEM
I hope this helps. Happy coding!
There is no need for configurationPid in the class annotation, and also you are missing service=Runnable.class which should follow immediate=true, i.e. the class declaration should look like:
#Component(immediate = true, service=Runnable.class)
#Designate(ocd=SchedulerConfiguration.class)
public class WeatherServiceScheduler implements Runnable {

How to use a custom ssh key location with Spring Cloud Config

I am trying to setup a Spring Cloud Config server that uses a custom location for the ssh private key.
The reason i need to specify a custom location for the key is because the user running the application has no home directory ..so there is not way for me to use the default ~/.ssh directory for my key.
I know that there is the option of creating a read-only account and provide the user/password in the configuration but the ssh way seams more clean.Is there a way I can setup this?
After reading a lot more code... I found a relatively simple work around to allow you to set whatever SSH keys you want.
First: Create a class as follows:
/**
* #file FixedSshSessionFactory.java
*
* #date Aug 23, 2016 2:16:11 PM
* #author jzampieron
*/
import org.eclipse.jgit.transport.JschConfigSessionFactory;
import org.eclipse.jgit.transport.OpenSshConfig.Host;
import org.eclipse.jgit.util.FS;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
/**
* Short Desc Here.
*
* #author jzampieron
*
*/
public class FixedSshSessionFactory extends JschConfigSessionFactory
{
protected String[] identityKeyPaths;
/**
* #param string
*/
public FixedSshSessionFactory( String... identityKeyPaths )
{
this.identityKeyPaths = identityKeyPaths;
}
/* (non-Javadoc)
* #see org.eclipse.jgit.transport.JschConfigSessionFactory#configure(org.eclipse.jgit.transport.OpenSshConfig.Host, com.jcraft.jsch.Session)
*/
#Override
protected void configure( Host hc, Session session )
{
// nothing special needed here.
}
/* (non-Javadoc)
* #see org.eclipse.jgit.transport.JschConfigSessionFactory#getJSch(org.eclipse.jgit.transport.OpenSshConfig.Host, org.eclipse.jgit.util.FS)
*/
#Override
protected JSch getJSch( Host hc, FS fs ) throws JSchException
{
JSch jsch = super.getJSch( hc, fs );
// Clean out anything 'default' - any encrypted keys
// that are loaded by default before this will break.
jsch.removeAllIdentity();
for( final String identKeyPath : identityKeyPaths )
{
jsch.addIdentity( identKeyPath );
}
return jsch;
}
}
Then register it with jgit:
...
import org.eclipse.jgit.transport.SshSessionFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
#SpringBootApplication
#EnableConfigServer
public class ConfigserverApplication
{
public static void main(String[] args) {
URL res = ConfigserverApplication.class.getClassLoader().getResource( "keys/id_rsa" );
String path = res.getPath();
SshSessionFactory.setInstance( new FixedSshSessionFactory( path ) );
SpringApplication.run(ConfigserverApplication.class, args);
}
}
For this example I'm storing the keys in the src/main/resources/keys folder and
I'm using the class loader to get at them.
The removeAllIdentities is important b/c JSch was loading my default ssh key before the one I specified and then Spring Cloud was crashing out b/c its encrypted.
This allowed me to successfully authenticate with bitbucket.
The FixedSshSessionFactory solution of #Jeffrey Zampieron is good. However it won't work if packaging the spring boot app as a fat jar.
Polish it a bit for working with fat jar,
/**
* #file FixedSshSessionFactory.java
* #date Aug 23, 2016 2:16:11 PM
* #author jzampieron
*/
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jgit.transport.JschConfigSessionFactory;
import org.eclipse.jgit.transport.OpenSshConfig.Host;
import org.eclipse.jgit.util.FS;
import org.springframework.util.StreamUtils;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
/**
* Short Desc Here.
*
* #author jzampieron
*/
#Slf4j
public class FixedSshSessionFactory extends JschConfigSessionFactory {
protected URL[] identityKeyURLs;
/**
* #param url
*/
public FixedSshSessionFactory(URL... identityKeyURLs) {
this.identityKeyURLs = identityKeyURLs;
}
/* (non-Javadoc)
* #see org.eclipse.jgit.transport.JschConfigSessionFactory#configure(org.eclipse.jgit.transport.OpenSshConfig.Host, com.jcraft.jsch.Session)
*/
#Override
protected void configure(Host hc, Session session) {
// nothing special needed here.
}
/* (non-Javadoc)
* #see org.eclipse.jgit.transport.JschConfigSessionFactory#getJSch(org.eclipse.jgit.transport.OpenSshConfig.Host, org.eclipse.jgit.util.FS)
*/
#Override
protected JSch getJSch(Host hc, FS fs) throws JSchException {
JSch jsch = super.getJSch(hc, fs);
// Clean out anything 'default' - any encrypted keys
// that are loaded by default before this will break.
jsch.removeAllIdentity();
int count = 0;
for (final URL identityKey : identityKeyURLs) {
try (InputStream stream = identityKey.openStream()) {
jsch.addIdentity("key" + ++count, StreamUtils.copyToByteArray(stream), null, null);
} catch (IOException e) {
logger.error("Failed to load identity " + identityKey.getPath());
}
}
return jsch;
}
}
I am having a similar problem because my default SSH key is encrypted with a password and therefore doesn't "just work", which makes sense because this is a head-less setup.
I went source-diving into Spring Cloud Config, org.eclipse.jgit and eventually ended up in com.jcraft.jsch. The short answer is that neither JGit nor Spring Cloud expose an obvious way to do this.
JSch clearly supports this feature within a JSch() instance, but you can't get at it from the Spring Cloud level. At least not that I could find in a hour or so of looking.

Use of resource-manager specific transaction demarcation API in EJB 3.x

Accordinong to EJB 3.0 specification: While an instance is in a transaction, the instance must not attempt to use the resource-manager specific transaction demarcation API (e.g. it must not invoke the
commit or rollback method on the java.sql.Connection interface or on the
javax.jms.Session interface) In 13.3.3 of Specification.
I tried one example - where in BEAN managed transaction I included java.sql.Connection.commit() - created Stateless bean in NetBeans as EE5, deployed on Glassfish 3.1 and container did not complain? Bean method updates the database without any errors in Glassfish log. Is this expected behavior?
Also, there is no such restriction on using java.sql.Connection.commit() for beans with container transaction managed transactions mentioned in specification.
Thanks
Branislav
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package ejb;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.ejb.*;
import javax.persistence.Transient;
import javax.sql.DataSource;
import javax.transaction.*;
/**
*
* #author bane
*/
#Stateless
#TransactionManagement(TransactionManagementType.BEAN)
public class MySession implements MySessionRemote {
#Resource(name = "SAMPLE")
private DataSource SAMPLE;
//
#Resource UserTransaction utx;
//gore je novi kod
#Override
public String getResult() {
return "This is my Session Bean";
}
public void doSomething() {
try {
Connection conn = SAMPLE.getConnection();
Statement stmt = conn.createStatement();
String q = "select * from BOOK";
String up = "update BOOK set PRICE = PRICE + 1";
utx.begin();
int num = stmt.executeUpdate(up);
System.out.println("num: "+num);
ResultSet rs = stmt.executeQuery(q);
//is conn.commit() legal?
conn.commit();
String name = null;
int price = 0;
while (rs.next()) {
name = rs.getString(2);
price = rs.getInt(3);
System.err.println(name+" , "+price);
}
utx.commit();
} catch (SQLException ex) {
Logger.getLogger(MySession.class.getName()).log(Level.SEVERE, null, ex);
} catch (Exception ex) {
Logger.getLogger(MySession.class.getName()).log(Level.SEVERE, null, ex);
}
}
// Add business logic below. (Right-click in editor and choose
// "Insert Code > Add Business Method")
}

Resources