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.
I am enabling message i18n in my Spring web app. For this, I have below code in my servlet.xml
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages/message"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
After adding above code, as soon as I hit my application in browser, I get below exception log:
SEVERE: Servlet.service() for servlet [default] in context with path [/ERP-Web] threw exception [Filter execution threw an exception] with root cause
java.lang.StackOverflowError
at org.springframework.context.support.ReloadableResourceBundleMessageSource.getMergedProperties(ReloadableResourceBundleMessageSource.java:235)
at org.springframework.context.support.ReloadableResourceBundleMessageSource.resolveCodeWithoutArguments(ReloadableResourceBundleMessageSource.java:176)
at org.springframework.context.support.AbstractMessageSource.getMessageInternal(AbstractMessageSource.java:209)
at org.springframework.context.support.AbstractMessageSource.getMessageFromParent(AbstractMessageSource.java:257)
where last 2 lines were repeated 100s of times and gives me StackoverflowException.
Exactly same exception is coming when I am using ResourceBundleMessageSource class.
My spring version is 4.3.6.RELEASE.
Below is content of my properties file
action.add.success = New {0} added successfully.
action.add.failure = Some error occurred in adding new {0}. Please try again later or contact administrator.
Sample project is on GitHub
I have tested your sample code in github and when running it has shown the error described, then modify the following:
Config:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages/message"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
Class:
#RequestMapping(method=RequestMethod.GET)
#ResponseBody
public String getMessage() {
String msg = messageSource.getMessage("hello.world", null, LocaleContextHolder.getLocale());
return msg;
}
hello.word is the property with text in your file with name message_en.properties.
With this modifications the code run.
Edit for unknown message codes:
I tried with unknown message codes and the error was repeated, so I look at the registry and found that there could be more than one beans with the same name (potential circular references), but I have not detected why this happens, but if you It needs to work you have to rename the beans like this.
<bean id="myMessageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages/message"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
and then use:
#Autowired
private MessageSource myMessageSource;
but i think this not resolve the principal problem with the circular potential error.
Very strange situation ;-)
The fundamental problem is that the messageSource gets auto-wired to itself (in the parentMessageSource property) because you use default-autowire="byType" this causes the stackoverflow exceptions for unknown message codes that messes up everything. Must say that logback adds mess to the mess as sometimes seems that the exception happens in its code, Log4J handles it better.
Autowiring is not good for big projects, and this your situation is a classical case of why, however if you must use it change the messageSource bean adding the following:
<property name="parentMessageSource"><null/></property>
In this way you wire yourself the parent and no autowiring happens.
This restores the normal situation in which not found messages are reported with a NoSuchMessageException
Then:
In controller you must request hello.world message, not message
You are missing a default resource, that is a no-locale-suffix file that represents the default locale or your application. In your case would be messages/message.properties To be simple the default locale of your application is that one for which you have all messages. Start with that and then add new languages (that might be incomplete).
Update
As far as I run your demo project:
Remove default-autowire="byType", which will set your message source's parent to itself, which causes stackoverflow;
Avoid LocaleContextHolder.getLocale(), which relay on system default locale;
Use right basename, which is different for ReloadableResourceBundleMessageSource and ResourceBundleMessageSource which solves following warning;
ResourceBundle [messages/message] not found for MessageSource: Can't find bundle for base name messages/message, locale en_US
Runnable example
StackTrace
As far as I could see from your stack trace, you may have three problems:
You don't supply arguments, but your property needs it;
The message source you have has cyclic dependency with its parent, which causes the StackOverflow (because AbstractMessageSource has a model like classloader, i.e. delegation to parent if it can't resolve);
I am not sure whether your properties is really found by message source, if it found, even with cyclic dependency, it will not StackOverflow;
Suggestions
When it comes to why there exists cyclic dependency, I can't tell whether it is a bug of spring or mis-configuration according to current info;
If you are not convenient to provide a example project, you may try 4.1.6 Relase, which I tried, works fine;
You may set log level to DEBUG or set breakpoint, to see whether you property file is really loaded;
The way you should use the ResourceBundleMessageSource is setting the path to the messages files on the basename property.
For example, if you have two messages files:
messages_en.properties
messages_es.properties
located at resources folder. Your bean configuration should be something like:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages" />
</bean>
Where messages is the prefix of the name of both files.
Maybe the Exception is thrown because Spring id trying to load the classpath automatically, and you have it included too, so it tries to load it again and again...
You can find a working example on Mkyong's.
This is what worked for me in my applicationContext.xml file:
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:i18n/message" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="defaultLocale" value="en"/>
</bean>
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<ref bean="localeChangeInterceptor" />
</property>
</bean>
Note that i put the properties files in the follwoing path :
src/main/resources/i18n/message_en.properties
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)
deployed webservice in jboss 5 with ws authentication related stuff mentioned in
beans.xml file.
same service worked well in tomcat 6 and when i deploy same service getting
java.lang.StackOverflowError
in jboss 5.in server.log apart form this error i didn't find any error.
when i comment from to then its working
fine.
I suspect jars conflict with cxf jars and jboss jars.
<jaxws:endpoint id="ping" implementor="cxfdemo.ws10.impl.PingServiceImpl"
address="/PingService">
<jaxws:inInterceptors>
<bean id="xxx" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<property name="properties">
<map>
<entry key="action" value="UsernameToken"/>
<entry key="passwordType" value="PasswordText" />
</map>
</property>
</bean>
</jaxws:inInterceptors>
</jaxws:endpoint>
2013-01-22 03:20:08,667 INFO QuartzScheduler_BpmClusteredScheduler-that missed their
scheduled fire-time.
2013-01-22 03:20:32,559 ERROR http-0.0.0.0-38080-3 [org.apache.catalina.core.ContainerBase
.[jboss.web].[localhost].[/PingWS].[cxf]] Servlet.service() for servlet cxf threw exception
java.lang.StackOverflowError
at java.security.AccessController.doPrivileged(Native Method)
at java.io.PrintWriter.<init>(PrintWriter.java:78)
at java.io.PrintWriter.<init>(PrintWriter.java:62)
</code>
Yes, the conflict is with the jars that come with JBoss as part of its webservices library. I tried the following and it worked:
Remove jbossws.deployer from /deployers
Remove jbossws.sar from /deploy
I've got my Spring Security custom login form working. It displays errors if the user has input bad credentials, or is expired, etc.
Looking inside spring-security-core-2.0.5.RELEASE.jar, I notice the following files in the org.springframework.security package:
messages.properties
messages_cs_CZ.properties
messages_de.properties
messages_fr.properties
...etc...
and notice that they have the localised versions of the strings.
Setting my browser's preferred language to French doesn't make the French version of the string appear. What am I missing?
PUK
Fixed it:
In my applicationContext.xml I include the Spring Security messages by adding another basename:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>com.myapp.web.my_messages</value>
<value>org.springframework.security.messages</value>
</list>
</property>
</bean>
In my web.xml I added another listener:
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>