Connection pool. call a procedure each time an operation is made - connection-pooling

Hei there, I'm working on a Primefaces 5/JSF 2/Mybatis webapp. My question is. To know each time who did what (on the app) we have to execute a method setUser(...). The company I'm working in right now, had a C# version of the app we are building now but there were no connection pools there so they only had to execute that procedure when the user logged in.
(right now we just call that method in the getSQLFactory method, which I know is not best practice... but that looked like the only viable solution to not add it manually in all our 200+ Mappers)
public static SqlSessionFactory getSqlSessionFactory() {
HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
ManagedNavUtils navyUtils = (ManagedNavUtils) session.getAttribute("navy");
if (navyUtils != null && navyUtils.getLoggedInUser() != null)
setLoggedInUser(navyUtils.getLoggedInUser());
return factory;
}
IS there a way to call the procedure each time something gets executed on the DB?
my mybatis-config.xml file with the relevant configuration:
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.username}" />
<property name="password" value="${database.password}" />
<!-- CONNECTION POOLING PROPERTIES -->
<property name="poolMaximumActiveConnections" value="20" />
<property name="poolMaximumIdleConnections" value="5" />
<property name="poolPingEnabled" value="false" />
</dataSource>
</environment>
</environments>

You can create mybatis plugin to intercept all queries.
But for your case better option is to set user only once that is during connection retrieval. Some connection pools allows custom initialization when connection is borrowed from the pool. Another possible option is to wrap DataSource which is used by mybatis.
For your case that is using datasource shipped with mybatis the easiest way it to wrap DataSource using custom DataSourceFactory.
First extend PooledDataSource like this:
class MyPooledDataSource extends PooledDataSource {
// all constructors should be defined but omitted for brevity
public Connection getConnection() throws SQLException {
Connection connection = super.getConnection();
setLoggedInUser(connection);
return connection;
}
public Connection getConnection(String username, String password) throws SQLException {
Connection connection = super.getConnection(username, password);
setLoggedInUser(connection);
return connection;
}
private void setLoggedInUser(Connection connection) {
// actual setting of logged in user
}
}
Then you need to define factory:
public class MyDataSourceFactory extends PooledDataSourceFactory {
public MyDataSourceFactory() {
this.dataSource = new MyPooledDataSource();
}
}
And modify mybatis-config.xml to make mybatis use your datasource factory:
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="org.myproject.MyDataSourceFactory">
<property name="driver" value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.username}" />
<property name="password" value="${database.password}" />
<!-- CONNECTION POOLING PROPERTIES -->
<property name="poolMaximumActiveConnections" value="20" />
<property name="poolMaximumIdleConnections" value="5" />
<property name="poolPingEnabled" value="false" />
</dataSource>
</environment>
</environments>

Related

Which is better CachingConnectionFactory.CacheMode Connection or Channel in Spring AMQP

Hi I have been using Spring AMQP with connection obtained from CachingConnectionFactory with the properties being shown below
<bean id="connectionFactory"
class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">
<constructor-arg value="rabbit-server-fqdn" />
<property name="virtualHost" value="some-vhost" />
<property name="username" value="username" />
<property name="password" value="password " />
<property name="channelCacheSize" value="25" />
</bean>
Now i need to change my mode to Connection as i need to check open connection
<bean id="connectionFactory"
class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">
<constructor-arg value="rabbit-server-fqdn" />
<property name="virtualHost" value="some-vhost" />
<property name="username" value="username" />
<property name="password" value="password " />
<property name="cacheMode" value="CONNECTION" />
<property name="channelCacheSize" value="25" />
</bean>
So
Q1. Will channelCacheSize will work ?
Q2. what will be default connection pool size in CachingConnectionFactory ?
Q3. Do i need to set additional property ?
The CHANNEL is better, because you don't need to create a new connection for each call, but reuse a shared one.
The Reference Manual has plenty of facts on the matter. One of them is when do you really need CONNECTION mode:
The use of separate connections might be useful in some environments, such as consuming from an HA cluster, in conjunction with a load balancer, to connect to different cluster members.
The shared connection is still can be traced for open/close state via ConnectionListener injected into that CachingConnectionFactory.

How to change the CachingConnectionFactory timeout setting

I have a use case where when the connectivity to rabbitmq goes down I need to manage the messages in different way.
I have a logic
RabbitTempate template // get template using API call
template.setReplyTimeout(10000);
template.convertAndSend(message);
But the problem is when the rabbitmq server connectivity goes down Spring AMQP automatically waits for connectivity to get resolved for 5 min
But because of that the client thread calling that particular logic waits for 5 min .
Is there any way i can change it , I am using CachingConnectionFactory
<bean id="connectionFactory"
class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">
<constructor-arg value="rabbit-server-fqdn" />
<property name="virtualHost" value="vhost" />
<property name="username" value="username" />
<property name="password" value="password" />
<property name="cacheMode" value="CONNECTION" />
<property name="channelCacheSize" value="25" />
</bean>
Is there any way I can override these settings from 5 min so that client API does not need to wait for such huge amount of time ?

Spring Security 3 custom remember me

i want to change remember me request parameter to override default parameter '_spring_security_remember_me'
and custom my remember me service to replace <remember-me /> namespace config.
so i config my remember me service:
<bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<property name="key" value="MY_REMEMBER_ME_KEY" />
<property name="cookieName" value="MY_REMEMBER_ME_COOKIE" />
<property name="parameter" value="remember" />
<property name="tokenValiditySeconds" value="1209600" />
<property name="useSecureCookie" value="true" />
<property name="userDetailsService" ref="userDetailsService" />
<property name="alwaysRemember" value="false" />
</bean>
namespace config:
<intercept-url pattern="/secure/index" access="ROLE_ADMIN" />
<remember-me services-ref="rememberMeServices"/>
when i run application and login. i find cookie is created then i close my ie and reopen.
entry the path '/secure/index', tomcat show me access is denied .
but i revert to Spring Security default config , all is ok.
i debug code find
RememberMeAuthenticationFilter#doFilter
...
Authentication rememberMeAuth = rememberMeServices.autoLogin(request, response);
...
//autoLogin(request, response) method code.
String rememberMeCookie = extractRememberMeCookie(request);
...
protected String extractRememberMeCookie(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if ((cookies == null) || (cookies.length == 0)) {
return null;
}
for (int i = 0; i < cookies.length; i++) {
if (cookieName.equals(cookies[i].getName())) {
return cookies[i].getValue();
}
}
return null;
}
in method extractRememberMeCookie(request), code request.getCookies() always return null when i use my custom remember me service, but i revert Spring Security default namespace <remember-me/> and do the same(clean Cookies - login - close ie - reopen - entry path '/secure/index'), i also find cookie is create .
and i debug the code i find request.getCookies() return the cookie name 'SPRING_SECURITY_REMEMBER_ME_COOKIE' and authentication successfully.
need other config to remember me authentication ?
but i don't know , would someone help me.
Your <remember-me /> still need key
this should be
<remember-me key="MY_REMEMBER_ME_KEY" services-ref="rememberMeServices"/>
As per the documentation of TokenBasedRememberMeServices,
An org.springframework.security.core.userdetails.UserDetailsService is
required by this implementation, so that it can construct a valid
Authentication from the returned
org.springframework.security.core.userdetails.UserDetails. This is
also necessary so that the user's password is available and can be
checked as part of the encoded cookie.
Perhaps your configuration is incorrect/incomplete.
This is actually an old post. But I just had the issue request.getCookies() null w/ Spring 4.
I've removed useSecureCookie = true to fix it.

How to dynamically decide <intercept-url> access attribute value in Spring Security?

In Spring Security we use the intercept-url tag to define the access for URLs as below:
<intercept-url pattern="/**" access="ROLE_ADMIN" />
<intercept-url pattern="/student" access="ROLE_STUDENT" />
This is hard coded in applicationContext-security.xml. I want to read the access values from a database table instead. I have defined my own UserDetailsService and I read the roles for the logged in user from the database. How do I assign these roles to the URL patterns during runtime?
The FilterInvocationSecurityMetadataSourceParser class in Spring-security (try Ctrl/Cmd+Shift+T in STS with the source code) parses the intercept-url tags and creates instances of ExpressionBasedFilterInvocationSecurityMetadataSource, that extends DefaultFilterInvocationSecurityMetadataSource that implements FilterInvocationSecurityMetadataSource that extends SecurityMetadataSource.
What I did is to create a custom class that implements FilterInvocationSecurityMetadataSource, OptionsFromDataBaseFilterInvocationSecurityMetadataSource. I used DefaultFilterInvocationSecurityMetadataSource as base to use urlMatcher, to implement the support() method and something like that.
Then you must to implement these methods:
Collection getAttributes(Object object), where you can access to database, searching for the 'object' being secured (normally the URL to access) to obtain the allowed ConfigAttribute's (normally the ROLE's)
boolean supports(Class clazz)
Collection getAllConfigAttributes()
Be careful with the later, because it's called at startup and maybe is not well configured at this time (I mean, with the datasources or persistence context autowired, depending on what are you using). The solution in a web environment is to configure the contextConfigLocation in the web.xml to load the applicationContext.xml before the applicationContext-security.xml
The final step is to customize the applicationContext-security.xml to load this bean.
For doing that, I used regular beans in this file instead of the security namespace:
<beans:bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<filter-chain-map path-type="ant">
<filter-chain pattern="/images/*" filters="none" />
<filter-chain pattern="/resources/**" filters="none" />
<filter-chain pattern="/**" filters="
securityContextPersistenceFilter,
logoutFilter,
basicAuthenticationFilter,
exceptionTranslationFilter,
filterSecurityInterceptor"
/>
</filter-chain-map>
</beans:bean>
You have to define all the related beans. For instance:
<beans:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<beans:property name="authenticationManager" ref="authenticationManager"></beans:property>
<beans:property name="accessDecisionManager" ref="affirmativeBased"></beans:property>
<beans:property name="securityMetadataSource" ref="optionsFromDataBaseFilterInvocationSecurityMetadataSource"></beans:property>
<beans:property name="validateConfigAttributes" value="true"/></beans:bean>
I know that is not a well explained answer, but it's not as difficult as it seems.
Just use the spring source as base and you will obtain what you want.
Debugging with the data in your database, will help you a lot.
Actually, spring security 3.2 do not encourage to do this according to http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/faq.html#faq-dynamic-url-metadata
but, it is possible (but not elegant) using http element in namespace with a custom accessDecisionManager..
The config should be:
<http pattern="/login.action" security="none"/>
<http pattern="/media/**" security="none"/>
<http access-decision-manager-ref="accessDecisionManager" >
<intercept-url pattern="/**" access="ROLE_USER"/>
<form-login login-page="/login.action"
authentication-failure-url="/login?error=1"
default-target-url="/console.action"/>
<logout invalidate-session="true" delete-cookies="JSESIONID"/>
<session-management session-fixation-protection="migrateSession">
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" expired-url="/login.action"/>
</session-management>
<!-- NO ESTA FUNCIONANDO, los tokens no se ponen en el request!
<csrf />
-->
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="test" password="test" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
<beans:bean id="accessDecisionManager" class="openjsoft.core.services.security.auth.CustomAccessDecisionManager">
<beans:property name="allowIfAllAbstainDecisions" value="false"/>
<beans:property name="decisionVoters">
<beans:list>
<beans:bean class="org.springframework.security.access.vote.RoleVoter"/>
</beans:list>
</beans:property>
</beans:bean>
The CustomAccessDecisionManager should be...
public class CustomAccessDecisionManager extends AbstractAccessDecisionManager {
...
public void decide(Authentication authentication, Object filter,
Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException {
if ((filter == null) || !this.supports(filter.getClass())) {
throw new IllegalArgumentException("Object must be a FilterInvocation");
}
String url = ((FilterInvocation) filter).getRequestUrl();
String contexto = ((FilterInvocation) filter).getRequest().getContextPath();
Collection<ConfigAttribute> roles = service.getConfigAttributesFromSecuredUris(contexto, url);
int deny = 0;
for (AccessDecisionVoter voter : getDecisionVoters()) {
int result = voter.vote(authentication, filter, roles);
if (logger.isDebugEnabled()) {
logger.debug("Voter: " + voter + ", returned: " + result);
}
switch (result) {
case AccessDecisionVoter.ACCESS_GRANTED:
return;
case AccessDecisionVoter.ACCESS_DENIED:
deny++;
break;
default:
break;
}
}
if (deny > 0) {
throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied",
"Access is denied"));
}
// To get this far, every AccessDecisionVoter abstained
checkAllowIfAllAbstainDecisions();
}
...
}
Where getConfigAttributesFromSecuredUris retrieve form DB de roles for the specific URL
I have kind of the same problem, basically I'd like to keep separate the list of intercept-url from the other springsecurity configuration section, the first to belong to the application configuration the latter to the product (core, plugin) configuration.
There is a proposal in the JIRA of spring, concerning this problem.
I don't want to give up to use the springsecurity namespace, so I was thinking to some possible solutions in order to deal with this.
In order to have the list of intercept-url dynamically created you have to inject the securitymetadatasource object in the FilterSecurityInterceptor.
Using springsecurity schema the instance of FilterSecurityInterceptor is created by the HttpBuilder class and there is no way to pass the securitymetadatasource as property defined in the schema configuration file, as less as using kind of workaround, which could be:
Define a custom filter, to be executed before FilterSecurityInterceptor, in this filter retrieving the instance FilterSecurityInterceptor (assuming a unique http section is defined) by the spring context and inject there the securitymetadatasource instance;
The same as above but in a HandlerInterceptor.
What do you think?
This the solution I've applied in order to split the list of intercept-url entries from the other spring security configuration.
<security:custom-filter ref="parancoeFilterSecurityInterceptor"
before="FILTER_SECURITY_INTERCEPTOR" />
........
<bean id="parancoeFilterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor" >
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="securityMetadataSource" ref="securityMetadataSource"/>
</bean>
The bean securityMetadataSource can be put either in the same configuration file or in another configuration file.
<security:filter-security-metadata-source
id="securityMetadataSource" use-expressions="true">
<security:intercept-url pattern="/admin/**"
access="hasRole('ROLE_ADMIN')" />
</security:filter-security-metadata-source>
Of course you can decide to implement your own securityMetadataSource bean by implementing the interface FilterInvocationSecurityMetadataSource.
Something like this:
<bean id="securityMetadataSource" class="mypackage.MyImplementationOfFilterInvocationSecurityMetadataSource" />
Hope this helps.
This is how it can be done in Spring Security 3.2:
#Configuration
#EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public SecurityConfigDao securityConfigDao() {
SecurityConfigDaoImpl impl = new SecurityConfigDaoImpl() ;
return impl ;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
/* get a map of patterns and authorities */
Map<String,String> viewPermissions = securityConfigDao().viewPermissions() ;
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry interceptUrlRegistry = http
.authorizeRequests().antMatchers("/publicAccess/**")
.permitAll();
for (Map.Entry<String, String> entry: viewPermissions.entrySet()) {
interceptUrlRegistry.antMatchers(entry.getKey()).hasAuthority(entry.getValue());
}
interceptUrlRegistry.anyRequest().authenticated()
.and()
...
/* rest of the configuration */
}
}
A simple solution that works for me.
<intercept-url pattern="/**/**" access="#{#customAuthenticationProvider.returnStringMethod}" />
<intercept-url pattern="/**" access="#{#customAuthenticationProvider.returnStringMethod}" />
customAuthenticationProvider is a bean
<beans:bean id="customAuthenticationProvider"
class="package.security.CustomAuthenticationProvider" />
in CustomAuthenticationProvider class create method:
public synchronized String getReturnStringMethod()
{
//get data from database (call your method)
if(condition){
return "IS_AUTHENTICATED_ANONYMOUSLY";
}
return "ROLE_ADMIN,ROLE_USER";
}

Spring LDAP - bind for successful connection

I'm trying to authenticate and then query our corporate LDAP using Spring LDAP and Spring security. I managed to make authentication work but when I attempt to run search I always get the following exception
In order to perform this operation a successful bind must be completed on the connection
After much research I have a theory that after I authenticate and before I can query I need to bind to connection. I just don't know what and how?
Just to mention - I can successfully browse and search our LDAP using JXplorer so my parameters are correct.
Here's section of my securityContext.xml
<security:http auto-config='true'>
<security:intercept-url pattern="/reports/goodbye.html"
access="ROLE_LOGOUT" />
<security:intercept-url pattern="/reports/**" access="ROLE_USER" />
<security:http-basic />
<security:logout logout-url="/reports/logout"
logout-success-url="/reports/goodbye.html" />
</security:http>
<security:ldap-server url="ldap://s140.foo.com:1389/dc=td,dc=foo,dc=com" />
<security:authentication-manager>
<security:authentication-provider ref="ldapAuthProvider">
</security:authentication-provider>
</security:authentication-manager>
<!-- Security beans -->
<bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldap://s140.foo.com:1389/dc=td,dc=foo,dc=com" />
</bean>
<bean id="ldapAuthProvider"
class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<constructor-arg>
<bean class="foo.bar.reporting.server.security.ldap.LdapAuthenticatorImpl">
<property name="contextFactory" ref="contextSource" />
<property name="principalPrefix" value="TD\" />
<property name="employee" ref="employee"></property>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="foo.bar.reporting.server.security.ldap.LdapAuthoritiesPopulator" />
</constructor-arg>
</bean>
<!-- DAOs -->
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="contextSource" />
Here's code snippet from LdapAuthenticatorImpl that performs authentication. No problem here:
#Override
public DirContextOperations authenticate(final Authentication authentication) {
// Grab the username and password out of the authentication object.
final String name = authentication.getName();
final String principal = this.principalPrefix + name;
String password = "";
if (authentication.getCredentials() != null) {
password = authentication.getCredentials().toString();
}
if (!("".equals(principal.trim())) && !("".equals(password.trim()))) {
final InitialLdapContext ldapContext = (InitialLdapContext)
this.contextFactory.getContext(principal, password);
// We need to pass the context back out, so that the auth provider
// can add it to the Authentication object.
final DirContextOperations authAdapter = new DirContextAdapter();
authAdapter.addAttributeValue("ldapContext", ldapContext);
this.employee.setqId(name);
return authAdapter;
} else {
throw new BadCredentialsException("Blank username and/or password!");
}
}
And here's another code snippet from EmployeeDao with my futile attempt to query:
public List<Employee> queryEmployeesByName(String query)
throws BARServerException {
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectclass", "person"));
filter.and(new WhitespaceWildcardsFilter("cn", query));
try {
// the following line throws bind exception
List result = ldapTemplate.search(BASE, filter.encode(),
new AttributesMapper() {
#Override
public Employee mapFromAttributes(Attributes attrs)
throws NamingException {
Employee emp = new Employee((String) attrs.get("cn").get(),
(String) attrs.get("cn").get(),
(String) attrs.get("cn").get());
return emp;
}
});
return result;
} catch (Exception e) {
throw new BarServerException("Failed to query LDAP", e);
}
}
And lastly - the exception I'm getting
org.springframework.ldap.UncategorizedLdapException:
Uncategorized exception occured during LDAP processing; nested exception is
javax.naming.NamingException: [LDAP: error code 1 - 00000000: LdapErr:
DSID-0C090627, comment: In order to perform this operation a successful bind
must be completed on the connection., data 0, vece]; remaining name
'DC=TD,DC=FOO,DC=COM'
It looks like your LDAP is configured to not allow a search without binding to it (no anonymous bind). Also you have implemented PasswordComparisonAuthenticator and not BindAuthenticator to authenticate to LDAP.
You could try modifying your queryEmployeesByName() method to bind and then search, looking at some examples in the doc.
I'm going to accept #Raghuram answer mainly because it got me thinking in the right direction.
Why my code was failing? Turned out - the way I wired it I was trying to perform anonymous search which is prohibited by the system - hence the error.
How to rewire example above to work? First thing (and ugly thing at that) you need to provide user name and password of user that will be used to access the system. Very counterintuitive even when you login and authenticated, even if you are using BindAuthenticator system will not attempt to reuse your credentials. Bummer. So you need to stick 2 parameters into contextSource definition like so:
<bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldap://foo.com:389/dc=td,dc=foo,dc=com" />
<!-- TODO - need to hide this or encrypt a password -->
<property name="userDn" value="CN=admin,OU=Application,DC=TD,DC=FOO,DC=COM" />
<property name="password" value="blah" />
</bean>
Doing that allowed me to replace custom implementation of authenticator with generic BindAuthenticator and then my Java search started working
I got the same error, couldn't find a solution.
Finally I changed the application pool identity to network service and everything worked like a charm.
(I have windows authentication and anonymous enabled on my site)

Resources