Spring-Data-Solr How to provide authentication data - spring-data-solr

how do i proivde authentication data for spring data solr server?
Here is what i have in configuration
<solr:solr-server id="solrServer" url="http://xxxxxxxx:8983/solr" />
<bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate" scope="singleton">
<constructor-arg ref="solrServer" />
</bean>
<bean id="searchRepository" class="com.bankofamerica.atmtech.repository.SolrJournalRepository">
<property name="solrOperations" ref="solrTemplate" />
</bean>
<bean id="App" class="App">
<property name="repo" ref="searchRepository" />
</bean>
I don't see any property where i can set it.

You cannot set Credentials directly but have to go through the factory.
#Bean
SolrTemplate solrTemplate() {
return new SolrTemplate(solrServerFactory());
}
#Bean
SolrServerFactory solrServerFactory() {
Credentials credentials = new UsernamePasswordCredentials("foo", "bar");
return new HttpSolrServerFactory(solrServer(), "collection1", credentials , "BASIC");
}
#Bean
SolrServer solrServer() {
return new HttpSolrServer("http://localhost:8983/solr");
}
I guess some kind of SolrAuthenticationProvider picked up and applied if present in application context would make sense in this case.

Related

Sql Connection in Spring Servicemix camel

Sql Connection in Spring Servicemix camel
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="jdbc:sqlserver://localhost:1433/orderdb"/>
<property name="username" value="abc"/>
<property name="password" value="pqr"/>
</bean>
When I try to make connection using dataSource.getConnection()
Not allowing please help
*****Connection Code **********
public class DatabaseBeanH2 {
private DataSource dataSource;
private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseBeanH2.class);
public DatabaseBeanH2(){}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void create() throws SQLException{
Statement sta = dataSource.getConnection().createStatement();
try {
sta.executeUpdate("CREATE TABLE orders ( id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, item VARCHAR(50), amount INT, description VARCHAR(300), processed BOOLEAN, consumed BOOLEAN);");
} catch (SQLException e) {
LOGGER.info("Table orders already exists");
}
}
public void destroy() throws SQLException {
dataSource.getConnection().close();
}
}
You have to setting up your database using following code
<!-- this is the JDBC data source which uses an in-memory only Apache Derby database -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver"/>
<property name="url" value="jdbc:derby:memory:orders;create=true"/>
<property name="username" value=""/>
<property name="password" value=""/>
</bean>
<!-- bean which creates/destroys the database table for this example -->
<bean id="initDatabase" class="org.apache.camel.example.sql.DatabaseBean"
init-method="create" destroy-method="destroy">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- configure the Camel SQL component to use the JDBC data source -->
<bean id="sql" class="org.apache.camel.component.sql.SqlComponent">
<property name="dataSource" ref="dataSource"/>
</bean>
Please check this link http://camel.apache.org/sql-example.html
You have to inject the dataSource bean in your DatabaseBeanH2 in the camel/spring context, something like this:
<bean id="databaseBean" class="my.package.DatabaseBeanH2">
<property name="dataSource" ref="dataSource" />
</bean>

Looping through Shiro LDAP Realm on Authenitcation Failure

I'm getting an odd error. If I pass in a valid user/password to my Shiro LDAP all is ok but if the combination is not valid it throws an exception and keeps on looping through the Shiro realm code. In the debugger it just stays in Shiro code except for my one override method:
public class MyJndiLdapRealm extends JndiLdapRealm {
public MyJndiLdapRealm () {
super();
}
#Override
protected AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token,
LdapContextFactory ldapContextFactory)
throws NamingException {
Object principal = token.getPrincipal();
Object credentials = token.getCredentials();
principal = getLdapPrincipal(token);
LdapContext ctx = null;
try {
ctx = ldapContextFactory.getLdapContext(principal, credentials);
//context was opened successfully, which means their credentials were valid. Return the AuthenticationInfo:
return createAuthenticationInfo(token, principal, credentials, ctx);
} finally {
LdapUtils.closeContext(ctx);
}
}
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/ldapLogin"/>
<property name="unauthorizedUrl" value="/ldapLogin"/>
<property name="successUrl" value="/ldapLogin"/>
<property name="filterChainDefinitions">
<value>
[urls]
/** = ssl[8443],authc, customAuthFilter
[main]
/logout = logout
</value>
</property>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realms">
<list>
<ref bean="authenticateLdapRealm"/>
<ref bean="authenticateDbRolesRealm"/>
<ref bean="DbAuthorizingRealm"/>
</list>
</property>
<property name="authenticator.authenticationStrategy">
<bean class="org.apache.shiro.authc.pam.AllSuccessfulStrategy"/>
</property>
</bean>
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<bean id="authenticateLdapRealm" class="security.MyJndiLdapRealm">
<property name="contextFactory" ref="contextFactory" />
<property name="userDnTemplate" value="cn={0},ou=REMOTE,o=OFF" />
</bean>
<bean id="contextFactory" class="org.apache.shiro.realm.ldap.JndiLdapContextFactory">
<property name="url" value="ldap://172.25.3.91:389"/>
</bean>
<bean id="authenticateDbRolesRealm" class="security.DbRolesRealm">
</bean>
<bean id="SwiDbAuthorizingRealm" class="security.DbAuthorizingRealm">
</bean>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
Somehow my custom filter was the problem. Went to PassThruAuthenticationFilter and the problem was solved.

Use JAAS for LDAP password with Spring security

I have a Java EE web application which uses an LDAP authentication. I use Spring security to connect to my LDAP with the following code:
<bean id="ldapContextSource" class="com.myapp.security.authentication.MySecurityContextSource">
<constructor-arg index="0" value="${ldap.url}" />
<constructor-arg index="1" ref="userConnexion" />
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="ldapAuthProvider" />
</security:authentication-manager>
<bean id="userConnexion" class="com.myapp.util.security.WebsphereCredentials">
<constructor-arg value="${ldap.authJndiAlias}" />
</bean>
<bean id="ldapAuthProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<constructor-arg>
<bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
<constructor-arg ref="ldapContextSource" />
<property name="userSearch" ref="userSearch" />
</bean>
</constructor-arg>
<constructor-arg>
<bean class="com.myapp.security.authentication.MyAuthoritiesPopulator" >
<property name="userService" ref="userService" />
</bean>
</constructor-arg>
<property name="userDetailsContextMapper" ref="myUserDetailsContextMapper"/>
<property name="hideUserNotFoundExceptions" value="false" />
</bean>
Actually, my bean WebsphereCredentials uses a WebSphere private class WSMappingCallbackHandlerFactory as in this response : How to access authentication alias from EJB deployed to Websphere 6.1
We can see it in the official websphere documentation: http://pic.dhe.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=%2Fcom.ibm.websphere.express.doc%2Finfo%2Fexp%2Fae%2Frsec_pluginj2c.html
But I don't want it because:
I think my application can access all JAAS logins in my WebSphere instance (not sure).
This class is defined in the HUGE IBM client library com.ibm.ws.admin.client-7.0.0.jar (42 Mo) => compilation slower, not present in my enterprise nexus
It's not portable, not standard
For information, I define the WebsphereCredentials constructor as this:
Map<String, String> map = new HashMap<String, String>();
map.put(Constants.MAPPING_ALIAS, this.jndiAlias);
Subject subject;
try {
CallbackHandler callbackHandler = WSMappingCallbackHandlerFactory.getInstance().getCallbackHandler(map, null);
LoginContext lc = new LoginContext("DefaultPrincipalMapping", callbackHandler);
lc.login();
subject = lc.getSubject();
} catch (NotImplementedException e) {
throw new EfritTechnicalException(EfritTechnicalExceptionEnum.LOGIN_CREDENTIAL_PROBLEM, e);
} catch (LoginException e) {
throw new EfritTechnicalException(EfritTechnicalExceptionEnum.LOGIN_CREDENTIAL_PROBLEM, e);
}
PasswordCredential cred = (PasswordCredential) subject.getPrivateCredentials().toArray()[0];
this.user = cred.getUserName();
this.password = String.valueOf(cred.getPassword());
Is there a way to use just Spring security and remove this dependency?
I have no idea how to combine http://static.springsource.org/spring-security/site/docs/3.1.x/reference/jaas.html and http://static.springsource.org/spring-security/site/docs/3.1.x/reference/ldap.html.
Maybe I must totally change my approach and use another way?
I assume your goal is to simply utilize the username / password that you configure in WebSphere to connect to the LDAP directory? If this is the case, you are not really trying to combine LDAP and JAAS based authentication. The JAAS support is really intended to be a way of using JAAS LoginModules to authenticate a user instead of using the LDAP based authentication.
If you are wanting to obtain the username and password without having a compile time dependency on WebSphere, you have a few options.
Eliminating Compile Time and Runtime Dependencies on WAS
One option is to configure the password in a different way. This could be as simple as using the password directly directly in the configuration file as shown in the Spring Security LDAP documentation:
<bean id="ldapContextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldap://monkeymachine:389/dc=springframework,dc=org"/>
<property name="userDn" value="cn=manager,dc=springframework,dc=org"/>
<property name="password" value="password"/>
</bean>
You could also configure the username password in JNDI. Another alternative is to use a .properties file with the Property. If you are wanting to ensure the password is secured, then you will probably want to encrypt the password using something like Jasypt.
Eliminating Compile Time dependencies and still configuring with WAS
If you need or want to use WebSphere's J2C support for storing the credentials, then you can do by injecting the CallbackHandler instance. For example, your WebsphereCredentials bean could be something like this:
try {
LoginContext lc = new LoginContext("DefaultPrincipalMapping", this.callbackHandler);
lc.login();
subject = lc.getSubject();
} catch (NotImplementedException e) {
throw new EfritTechnicalException(EfritTechnicalExceptionEnum.LOGIN_CREDENTIAL_PROBLEM, e);
} catch (LoginException e) {
throw new EfritTechnicalException(EfritTechnicalExceptionEnum.LOGIN_CREDENTIAL_PROBLEM, e);
}
PasswordCredential cred = (PasswordCredential) subject.getPrivateCredentials().toArray()[0];
this.user = cred.getUserName();
this.password = String.valueOf(cred.getPassword());
Your configuration would then look something like this:
<bean id="userConnexion" class="com.myapp.util.security.WebsphereCredentials">
<constructor-arg ref="wasCallbackHandler"/>
</bean>
<bean id="wasCallbackHandler"
factory-bean="wasCallbackFactory"
factory-method="getCallbackHandler">
<constructor-arg>
<map>
<entry
value="${ldap.authJndiAlias}">
<key>
<util:constant static-field="com.ibm.wsspi.security.auth.callback.Constants.MAPPING_ALIAS"/>
</key>
</entry>
</map>
</constructor-arg>
<constructor-arg>
<null />
</constructor-arg>
</bean>
<bean id="wasCallbackFactory"
class="com.ibm.wsspi.security.auth.callback.WSMappingCallbackHandlerFactory"
factory-method="getInstance" />
Disclaimer
CallbackHandler instances are not Thread safe and generally should not be used more than once. Thus it can be a bit risky injecting CallbackHandler instances as member variables. You may want to program in a check to ensure that the CallbackHandler only used one time.
Hybrid Approach
You could do a hybrid approach that always removes the compile time dependency and allows you to remove the runtime dependency in instances where you might not be running on WebSphere. This could be done by combining the two suggestions and using Spring Bean Definition Profiles to differentiate between running on WebSphere and a non-WebSphere machine.

Alfresco set permissions for node in bootstrap

I have a problem with setting permission for existing node("Sites" folder). I have a group and I need to give her full control permission for "Sites" folder. I'm used the next xml for this
<cm:folder view:childName="cm:Sites">
<view:acl>
<view:ace view:access="ALLOWED">
<view:authority>GROUP_NOTEBOOK_PROJECT_CREATOR_GROUP</view:authority>
<view:permission>FullControl</view:permission>
</view:ace>
</view:acl>
<view:properties>
<cm:name>Sites</cm:name>
<sys:node-uuid>1e6f0610-a018-4966-ab37-c71e809dc6ed</sys:node-uuid>
</view:properties>
</cm:folder>
and next config context
<bean id="com.agilent.datastore.notebook.server.systemBootstrap" class="org.alfresco.repo.module.ImporterModuleComponent"
parent="module.baseComponent">
<property name="moduleId" value="${artifactId}" />
<property name="name" value="${name}" />
<property name="description" value="${description}" />
<property name="sinceVersion" value="${noSnapshotVersion}.${buildNumber}" />
<property name="appliesFromVersion" value="${noSnapshotVersion}.${buildNumber}" />
<!-- Uncomment next line if you want to execute bootstrap again -->
<!-- property name="executeOnceOnly" value="false" / -->
<property name="importer" ref="spacesBootstrap" />
<property name="bootstrapViews">
<list>
<props>
<prop key="uuidBinding">UPDATE_EXISTING</prop>
<prop key="path">/${spaces.company_home.childname}</prop>
<prop key="location">alfresco/extension/agilent/sites.acp</prop>
But when I'm bootstrap this folder I got exception Cannot insert duplicate key row in object 'dbo.alf_child_assoc' with unique index 'parent_node_id'.; nested exception is java.sql.SQLException: Cannot insert duplicate key row in object 'dbo.alf_child_assoc' with unique index 'parent_node_id'.
The best way to achieve what you want is to write a patch, that is a java class that extends the alfresco AbstractPatch.java class.
In the applyInternal method you first get hold of the sites-folder preferable with an xpath-search since this uses the nodeService in the background. Solr won't be available during the execution of this code since the patch is ran during bootstrap.
Declare you patch in a spring context file like this:
<bean id="patch.setPermissionsOnSitesFolderPatch" class="org.yourdomain.alfresco.patch.SetPermissionOnSitesFolderPatch" parent="basePatch">
<property name="id">
<value>patch.patch.setPermissionsOnSitesFolderPatch</value>
</property>
<property name="description">
<value>patch.setPermissionsOnSitesFolderPatch.description</value>
</property>
<property name="fixesFromSchema">
<value>0</value>
</property>
<property name="fixesToSchema">
<value>${version.schema}</value>
</property>
<property name="targetSchema">
<value>10000</value>
</property>
<property name="force" value="true" />
<property name="repository" ref="repositoryHelper"/>
</bean>
To complete the answer by #billerby you will also need a Java class to go along with that snippet. The Alfresco docs contain a good example. Using that this is what I came up with for my use-case:
Note I'm using Lombok, but that's just for convenience
public class UpdatePermissionsPatch extends AbstractPatch {
/**
* The Alfresco Service Registry that gives access to all public content services in Alfresco.
*/
#Setter private ServiceRegistry serviceRegistry;
/* Properties */
#Setter private String path;
#Setter private String authority;
#Setter private String permission;
#Setter private boolean allowed;
/** This will clear permissions for the specified authority if set to true */
#Setter private boolean clearPermissions;
private String getSuccessId() {
return getId() + ".result";
}
private String getErrorId() {
return getId() + ".error";
}
#Override
protected String applyInternal() throws Exception {
log.info("Starting execution of patch: {}", I18NUtil.getMessage(getId()));
// Get the store reference for the Repository store that contains live content
StoreRef store = StoreRef.STORE_REF_WORKSPACE_SPACESSTORE;
// Get root node for store
NodeRef rootRef = serviceRegistry.getNodeService().getRootNode(store);
// Do the patch work
setPermissions(getWipNodeRef(rootRef));
log.info("Finished execution of patch: {}", I18NUtil.getMessage(getId()));
return I18NUtil.getMessage(getSuccessId());
}
private void setPermissions(NodeRef nodeRef) {
PermissionService permsService = serviceRegistry.getPermissionService();
if (clearPermissions) {
permsService.clearPermission(nodeRef, authority);
}
permsService.setPermission(nodeRef, authority, permission, allowed);
}
private NodeRef getWipNodeRef(NodeRef rootNodeRef) {
NamespaceService nsService = serviceRegistry.getNamespaceService();
List<NodeRef> refs = searchService.selectNodes(rootNodeRef, path, null, nsService, false);
if (refs.size() != 1) {
throw new AlfrescoRuntimeException(I18NUtil.getMessage(getErrorId(),
String.format("Node could not be found, XPATH query %s returned %i nodes.", path, refs.size())
));
}
return refs.get(0);
}
}
And your bootstrap context xml will need to include something like this:
<bean
id="org.tutorial.folderUpdateWipPermissions"
class="org.tutorial.patch.UpdatePermissionsPatch"
parent="basePatch"
>
<property name="id" value="org.tutorial.bootstrap.patch.folderUpdateWipPermissions" />
<property name="description" value="org.tutorial.bootstrap.patch.folderUpdateWipPermissions.description" />
<property name="fixesFromSchema" value="0" />
<property name="fixesToSchema" value="${version.schema}" />
<property name="targetSchema" value="100003" />
<property name="serviceRegistry">
<ref bean="ServiceRegistry"/>
</property>
<property name="path" value="/${spaces.company_home.childname}/cm:Work_x0020_In_x0020_Progress" />
<property name="authority" value="GROUP_MyGroup" />
<property name="permission" value="Consumer" />
<property name="allowed" value="true" />
<property name="clearPermissions" value="true" />
</bean>

Spring AfterReturningAdvice firing before transaction commits

I seem to be having a weird problem. In our services layer, we are using WCF with nHibernate and Spring.NET 1.3.0.20349. I don't have the option to upgrade spring to the next version.
I have save methods on a service that has AfterReturningAdvices which are required to make another service call that calls into the Db and uses the ID of the saved object. The problem is that the interceptor is firing before the transaction commits which is causing the next service call to return empty objects
After some reading, my understanding of Springs Interceptors are :
The pre-interceptors beforeadvice methods run
Spring starts the transaction
The post-interceptors beforeadvice methods run
The main service method runs
The post-interceptors afterreturning advice methods run
Spring commits the transaction
The pre-interceptors afterreturning advice methods run
My web.config has the following:
<object id="InsertPointcut" type="Spring.Aop.Support.NameMatchMethodPointcutAdvisor, Spring.Aop">
<property name="advice">
<ref local="afterAddInterceptor"/>
</property>
<property name="MappedNames">
<list>
<value>AddToEvent</value>
</list>
</property>
</object>
<object id="UpdatePointcut" type="Spring.Aop.Support.NameMatchMethodPointcutAdvisor, Spring.Aop">
<property name="advice">
<ref local="afterUpdateInterceptor"/>
</property>
<property name="MappedNames">
<list>
<value>Update</value>
</list>
</property>
</object>
<object id="ServiceProxy" type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
<property name="PlatformTransactionManager" ref="transactionManager"/>
<property name="TransactionAttributeSource" ref="attributeTransactionAttributeSource"/>
<property name="target">
<object id="Service" type="Service, Service" init-method="init">
<constructor-arg ref="sessionFactory" />
<property name="EventRepository" ref="eventRepository" />
</object>
</property>
<property name="preInterceptors">
<list>
<ref local="throwsAdvice"/>
<ref local="InsertPointcut"/>
<ref local="UpdatePointcut"/>
</list>
</property>
</object>
Can anyone help?
[Update]
In order to avoid making code changes to my services, I implemented the ITransactionSynchronization interface on my advice and registered it. That way, in the AfterCompletion method, I can do my work after spring & nHibernate has committed. I'm not sure if there is a better way to handle this but it seems to work.
public class AfterUpdateInterceptor : IAfterReturningAdvice, ITransactionSynchronization
{
private int id;
[Transaction]
public void AfterReturning(object returnValue, MethodInfo method, object[] args, object target)
{
TransactionSynchronizationManager.RegisterSynchronization(this);
if (args == null || args.Length == 0)
{
return;
}
id = PropertyHelper.GetIdPropertyValue<IUpdateContract>(args);
}
public void Suspend()
{
}
public void Resume()
{
}
public void BeforeCommit(bool readOnly)
{
}
public void AfterCommit()
{
}
public void BeforeCompletion()
{
}
public void AfterCompletion(TransactionSynchronizationStatus status)
{
if (status != TransactionSynchronizationStatus.Committed) return;//.com msg not sent.
if (id > 0)
{
XmlSender.SendXmlUpdate(MessageType.Update, id);
}
id = 0;
}
}
From looking at the source of the TransactionProxyFactoryObject's AfterPropertySet Method, I think that is in fact the order of the applied advices. So you should have a AfterReturningAdvice configured in your pre-interceptors.
If this isn't called, it might be a bug and I would suggest to ask in the spring.net forums.
Another way to get called when an transaction is comitted is the ITransactionSynchronization Interface which can be registered with the TransactionSynchronizationManager.