I am implementing a multitenant application with the spring security saml extention.
I have a Service Provider (SP) for each tenant.
All SPs runs on the same server exposed with SP-specific 2nd level domain:
sp1.myapp.com/myapi/1/
sp1.myapp.com/myapi/2/
In each SP metadata file I have configured the tenant-specific AssertionConsumerService.
When I test the SSO Login, I get a KO on SP side when it gets the response of the Identity Provider (IDP).
On Log side i see only:
ERROR [BaseSAMLMessageDecoder] SAML message intended destination endpoint 'https://sp1.myapp.com/myapi/saml/SSO' did not match the recipient endpoint 'https://default.myapp.com/myapi/saml/SSO'
Where the 'https://default.myapp.com/myapi/saml/SSO' is the URL set as serverName of the load balancer context provider:
<bean id="lbContextProvider" class="org.springframework.security.saml.context.SAMLContextProviderLB" init-method="afterPropertiesSet">
<property name="metadata" ref="metadata" />
<property name="keyManager" ref="keyManager" />
<property name="scheme" value="https" />
<property name="serverName" value="default.myapp.com" />
<property name="contextPath" value="/myapi" />
<property name="serverPort" value="443" />
<property name="includeServerPortInRequestURL" value="true" />
</bean>
Question
In the docs.spring.io/spring-security-saml I see that
Service provider can now define multiple assertion consumer endpoints with same binding
How can I configure it?
Does it conflict with load balancer context provider?
Can I provide multiple AssertionConsumerService with different 2nd level domains without reproduction this conflict?
I already tested:
This question seems to be fixed with the LB, but anyone knows if I can provide multiple serverName to load balancer context provider (maybe with a dynamic pick)?
Disable the checking of the InResponseToField as suggested at ch.13 docs.spring.io/spring-security-saml and for this and this question.
Configure the defaultTargetUrl of the successRedirectHandler (where I am using a custom superclass of org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler) as suggested for this question. In addition this solution is not multitenant.
<bean id="successRedirectHandler" class="org.MySamlAuthenticationSuccessHandler"
init-method="afterPropertiesSet">
<property name="contextPath" value="/myapi" />
<property name="defaultTargetUrl" value="https://default.myapp.com/myapi/saml/SSO"/>
<property name="requireProxyWrapping" value="false"/>
</bean>
Customize SAMLContextProviderLB by extending SamlContextProviderLB.
In custom class, add constructor and initialize with default values.
Override getLocalAndPeerEntity/getLocalEntity/populateLocalEntityId. In each of this method set lbDomain based on domain in requestURL.
above approach worked for me.
Related
We are implementing XA transaction between MQ and database and trying to create a connection factory as a service in karaf as per the below link.
https://access.redhat.com/documentation/fr-fr/red_hat_fuse/7.2/html/apache_karaf_transaction_guide/using-jms-connection-factories#manual-deployment-connection-factories
The MQ we are using is IBM and we are connecting to it through camel.
The karaf service is exposed from the same bundle that is going to use it. This is done through blueprint xml file present in the src/main/resources/OSGI-INF/blueprint folder.
When we use (through JNDI) the connection factory exposed as a service for setting the connection factory to be used by the JmsComponent of camel, we are able to get message from the queue but not able to put message into the queue. There is no error when the put operation fails and hence, the database gets updated with success. This happens specifically when using JmsPoolXAConnectionFactory as the pool connection factory. If we change it to JmsPoolConnectionFactory, the put operation works and the message is added to the queue.
Below are the sample routes for get and put to queue.
GET:
from("mq:queue:{{queueName}}")
.process(new CustomProcessor1())
.to("direct:call-sp")
.end();
from("direct:call-sp")
.to("sql-stored:call-sp")
.end();
PUT:
from("vm:send")
.process(new CustomProcessor2())
.to("mq:queue:{{queueName}}")
.to("sql-stored:update-sp")
.to("vm:nextroute")
.end();
Camel JmsComponent Configuration in camel-context.xml:
<reference id="ptm" interface="org.springframework.transaction.PlatformTransactionManager" />
<reference id="connectionFactory" interface="javax.jms.ConnectionFactory" filter="(osgi.jndi.service.name=jms/mq)" availability="optional" />
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="transacted" value="false" />
<property name="connectionFactory" ref="connectionFactory" />
<property name="transactionManager" ref="ptm" />
</bean>
<bean id="mq" class="org.apache.camel.component.jms.JmsComponent">
<property name="configuration" ref="jmsConfig" />
<property name="destinationResolver" ref="customDestinationResolver" />
</bean>
<bean id="customDestinationResolver" class="com.example.CustomDestinationResolver">
</bean>
Is there any put related specific configuration that we are missing?
To coordinate XA transactions, you need a transaction manager which implements the Java Transaction API (JTA).
Therefore, I think you need to use a JtaTransactionManager rather than a org.springframework.transaction.PlatformTransactionManager.
Check this out:
https://tomd.xyz/camel-xa-transactions-checklist/
I have been researching how to implement a web service client policies from a .wsdl file.
The policies of the web services implicates a signature and encryption using a .jks file with the necessary keys (asymmetric privateKey for signing, and a symmetric privateKey for encryption). The policy is: username:oracle/wss10_username_token_with_message_protection_service_policy.
I am able to make the .xsd files (request, response and service objects) using the wsimport tool for java (or with cxf or axis2). What i can't resolve is how to make the correct policy.
Is there any way to automatically generate the policies from the .wsdl or do i have to make them by myself
The username:oracle/wss10_username_token_with_message_protection_service_policy is solved with spring ws this way:
<!-- == Ougoing interceptor == -->
<bean id="loginOutgoingWss4jSecurityInterceptor" class="org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor">
<property name="securementActions" value="Timestamp Signature Encrypt" />
<!-- == Set Outgoing Signature properties == -->
<property name="securementUsername" value="alias"/>
<property name="securementPassword" value="aliasPass"/>
<property name="securementSignatureKeyIdentifier" value="DirectReference"/>
<property name="securementSignatureCrypto" ref="cryptoFactoryBean" />
<property name="securementSignatureParts" value="{Element}{}Body;{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;" />
<!-- == Set Outgoing Encryption properties == -->
<property name="securementEncryptionUser" value="alias"/>
<property name="securementEncryptionCrypto" ref="cryptoFactoryBean" />
<property name="securementEncryptionKeyIdentifier" value="DirectReference"/>
<property name="securementEncryptionParts" value="{Content}{}Body;" />
</bean>
<!-- == Incoming interceptor == -->
<bean id="loginIncomingWss4jSecurityInterceptor" class="org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor">
<property name="validationActions" value="Timestamp Signature Encrypt" />
<!-- == Set Validations Response, This validate signature and decrypts response == -->
<property name="validateResponse" value="true" />
<!-- The lower operation validation. Less time consume-->
<property name="validateRequest" value="false" />
<property name="enableSignatureConfirmation" value="false"/>
<!-- == Set Incoming Signature/Decryption keystore == -->
<property name="validationDecryptionCrypto" ref="cryptoFactoryBean" />
<property name="validationSignatureCrypto" ref="cryptoFactoryBean" />
<!-- Sets the {#link org.apache.ws.security.WSPasswordCallback} handler to use when validating messages -->
<property name="validationCallbackHandler">
<bean class="org.springframework.ws.soap.security.wss4j2.callback.KeyStoreCallbackHandler">
<property name="privateKeyPassword" value="aliasPass"/>
</bean>
</property>
</bean>
If you are using policies in WS-SecurityPolicy (1.1 or later) in your wsdl, no need to generate policies nor make them on client side with Apache CXF. With WS-SecurityPolicy, CXF's security runtime is policy driven.
1) You follow CXF's WSDL-first approach to generate the client code, using either wsdl2java command-line tool or Maven cxf-codegen-plugin (wsdl2java goal). This is described in CXF doc's How to develop a client.
2) Following CXF's doc on WS-SecurityPolicy usage, you configure the client security properties for the wsdl port you want to use, either using JAX-WS API (on the client's RequestContext) or Spring XML configuration. For the list of possible properties, there are the generic XML security ones and WS-Security-specific ones. Example with Spring XML for UsernameToken policy (from Glen Mazza's blog samples ):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<jaxws:client name="{http://www.example.org/contract/DoubleIt}DoubleItPort" createdFromAPI="true">
<!-- Use this for the UsernameToken Symmetric Binding w/X.509 for secret key derivation -->
<jaxws:properties>
<entry key="ws-security.username" value="alice"/>
<entry key="ws-security.callback-handler" value="client.ClientPasswordCallback"/>
<entry key="ws-security.encryption.properties" value="clientKeystore.properties"/>
<entry key="ws-security.encryption.username" value="myservicekey"/>
</jaxws:properties>
<!-- Use this for the UsernameToken Symmetric Binding w/UT password for secret key derivation -->
<!--jaxws:properties>
<entry key="ws-security.username" value="alice"/>
<entry key="ws-security.callback-handler" value="client.ClientPasswordCallback"/>
</jaxws:properties-->
</jaxws:client>
</beans>
Put this in /cxf.xml on the class path. Warning: the example is using a CallbackHandler subclass (client.ClientPasswordCallback in this example) to provide the password. So you'll need to provide your own implementation.
3) Back to CXF doc's How to develop a client - last part - in the application code, initialize the client using JAX-WS API with arguments: a) the location of the WSDL (URL) having the WS-SecurityPolicy policies (you already have that, as far as I understand); b) service and port's QNames to be used by the client, as defined in the WSDL:
final Service service = Service.create(wsdlLocation, SERVICE_QNAME);
final DoubleItPortType transportPort = service.getPort(PORT_QNAME, DoubleItPortType.class);
4) Make sure you have cxf-rt-ws-policy and cxf-rt-ws-security modules on the classpath at runtime to enable WS-SecurityPolicy support.
I am new to spring. Admins of my spring based web app want to configure settings from the web interface, so users can authenticate against LDAP server with their company username and password.
Change in LDAP settings should be possible without restarting the application. This might happen during a 'migration' or whatever reason. I have a couple beans, which need to be refreshed after the admin saves new settings for the LDAP server:
<bean id="ldapServer" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg>
<list>
<value>${ldap.url1}</value>
...
</list>
</constructor-arg>
<constructor-arg value="${ldap.basedn}"</constructor-arg>
<property name="referral" value="${ldap.referral}" />
<property name="baseEnvironmentProperties">...</property>
<property name="userDn" value="${ldap.username}" />
<property name="password" value="${ldap.password}" />
</bean>
I am using Springframework 3.1.2. The problem is, there are constructor arguments, which I want to change and not affect other running jobs. I tried playing with Scoped proxy, but not to much success yet:
<bean id="ldapServer" scope="prototype" ...>
<aop:scoped-proxy/>
I was successful though to get ldapServer to reinstantiate, when using prototype scope by running this piece of code:
#Controller
public class LDAPSettingsController implements ApplicationContextAware {
public ModelAndView handleRequest(...) {
DefaultSpringSecurityContextSource ldap;
ldap = context.getParentBeanFactor().getBean("ldapServer");
System.out.println(ldap.hashCode());
return new ModelAndView(new RedirectView('login.jsp'));
}
...
}
Are scopes and proxies here the way to go, or is the another mechanism in Spring to reflect configuration changes into a running program instance?
UPDATE: Clear up the question.
UPDATE: The root problem with the AOP proxies was following root exception:
java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
What worked was adding proxy-target-class="false" attribute to the <aop:scoped-proxy/> tag. I created a new scope, which works better than prototype - It destroys beans on settings update. Now I have this in my beans.xml:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="ldap">
<ref bean="ldapScope" />
</entry>
</map>
</property>
</bean>
<bean id="ldapScope" class="com.myapp.SettingsScope" />
<bean id="ldapServer" scope="ldap" ...>
<aop:scoped-proxy proxy-target-class="false"/>
<constructor-args>
<list><value>${ldap.url1}</value> .. </list>
</constructor-args>
...
</bean>
I also have a controller for LDAP settings into which I inject ldapScope and I call a method which destroys current life-cycle objects and starts a new life-cycle every time, user presses the apply button.
PS: Not sure if I handle the life-cycle "re-start" in the right way - people my way to look for auto-start beans and start them after such event happens (i.e.: Setting -> Apply)
I'm new to Spring security and cas.
In my project I have a cas(CenteralAuthenticationServer) server and a service server.
I want to implement Switch user filter for some users in my application.
Where I should put these lines?
<bean id="switchUserProcessingFilter" class="org.springframework.security.web.authentication.switchuser.SwitchUserFilter">
<property name="userDetailsService" ref="userDetailsService" />
<property name="switchUserUrl" value="/j_spring_security_switch_user" />
<property name="exitUserUrl" value="/j_spring_security_exit_user" />
<property name="targetUrl" value="/index.jsp" />
</bean>
In my cas project or in my web application?
Should I tell tomcat to use this filter in web.xml?
Is there any implementation example?
Should I create java class to implement this fitler?
Add it in your web application (dispatcher-servlet.xml). Check this example if you need.
switch user link
We have many CXF web services running under Tomcat. For each of the services, there is a beans config file, with each one having an entry like the one below. The variable ${JMX.PORT} is replaced with the assigned port at runtime. Each service has a separate port. I have looked everywhere but cannot confirm that this is correct. I do know, however, that having the same port for two or more services causes startup issues. So, I am looking for confirmation that each service should have its own port. Note - When I look at a service remotely using JConsole, with a connection string such as service:jmx:rmi:///jndi/rmi:/192.168.29.35:9912/jmxrmi, I can also see the other services, even though they have different port assignments. That makes no sense, unless there are some kind of shared resources. Can anyone help me to understand this? Thanks!
<bean id="org.apache.cxf.management.InstrumentationManager" class="org.apache.cxf.management.jmx.InstrumentationManagerImpl">
<property name="bus" ref="cxf" />
<property name="enabled" value="true" />
<property name="threaded" value="false" />
<property name="daemon" value="false" />
<property name="usePlatformMBeanServer" value="true"/>
<property name="JMXServiceURL" value="service:jmx:rmi:///jndi/rmi://localhost:${JMX.PORT}/jmxrmi" />
</bean>