Spring Social Login: How to add more than one app of the same social provider (f.e. Facebook)? - spring

My Spring MVC web application is serving simultanously three different web shops with three different domains (let's call them domain1.com, domain2.com and domain3.com).
For each of these shops I need to offer an own Social Login (with custom login screen title, custom data privacy statement, ...). Therefore I need to create three different social provider (f.e. facebook) apps.
In Spring Social - from my understanding - I'm allowed to add only one FacebookConnectionFactory and hereby only one provider app.
How can I despite that add these three different facebook apps to Spring Social? Is Spring Social capable to manage this? Are there workarounds existing?

May be I answered too late for the OP but this could be usefull for other developers.
I implemented a workaround for this issue defining my own "Registries" as follow:
<bean id="myConnectionFactoryRegistries" class="package.ShopsFactoryRegistries">
<property name="registries">
<map key-type="java.lang.String">
<entry key="shop1Key" value-ref="connectionFactoryRegistryShop1" />
<entry key="shop2Key" value-ref="connectionFactoryRegistryShop2" />
</map>
</property>
</bean>
<bean id="connectionFactoryRegistryShop1"
class="org.springframework.social.connect.support.ConnectionFactoryRegistry">
<property name="connectionFactories">
<list>
<bean
class="org.springframework.social.facebook.connect.FacebookConnectionFactory">
<constructor-arg value="${facebook.apikey.shop1}" />
<constructor-arg value="${facebook.apisecret.shop1}" />
</bean>
</list>
</property>
</bean>
<bean id="connectionFactoryRegistryShop2"
class="org.springframework.social.connect.support.ConnectionFactoryRegistry">
<property name="connectionFactories">
<list>
<bean
class="org.springframework.social.facebook.connect.FacebookConnectionFactory">
<constructor-arg value="${facebook.apikey.shop2}" />
<constructor-arg value="${facebook.apisecret.shop2}" />
</bean>
</list>
</property>
</bean>
And implement a factory in order to retrieve the proper ConnectionFactoryRegistry related to the "current" shop (identified by the shopKey).
public class ShopsFactoryRegistries
{
private Map<String, ConnectionFactoryRegistry> registries;
public ConnectionFactoryRegistry getRegistryForShopKey(String shopKey)
{
return registries.get(shopKey);
}
//getter and setter for registries
}
With this code you can retrieve the facebookConnectionFactory for the shop1:
String shopKey = "shop1Key";
FacebookConnectionFactory facebookConnectionFactory = (FacebookConnectionFactory) myConnectionFactoryRegistries.getRegistryForShopKey(shopKey).getConnectionFactory(FACEBOOK);

Related

Using a MethodInterceptor to wrap calls to protected method

I would like to use XML based Spring configuration to wrap calls to a protected method in a 3rd party class. I have wired up some spring classes from org.springframework.aop.support. It works for public methods, but it fails for protected ones:
<bean id="sampleAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="proxyTargetClass" value="true" />
<property name="beanNames">
<list>
<value>thrirdPartyBean</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>sampleAdvisor</value>
</list>
</property>
</bean>
<bean id="sampleMethodNamePointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
<property name="mappedNames">
<list>
<value>publicMethodThatWorks</value>
<value>protectedMethodThatDoesNotWork</value>
</list>
</property>
</bean>
<bean id="sampleAdvice" class="sample.MyMethodInterceptor" />
<bean id="sampleAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="sampleMethodNamePointcut" />
<property name="advice" ref="sampleAdvice" />
</bean>
How can I tweak this to work with protected methods ?
As the linked question/answer in the comments states, Springs AOP proxies can only apply to public methods.
With JDK proxies, this isn't possible because the proxy only has your target object's interface types so you can only interact with it through its public methods (remember that all methods declared in an interface are public).
With GGLIB proxies, because the proxy does have the target object's class type, you can interact with its protected methods. I would think for reasons of consistency between proxying mechanisms they would not allow it.

Spring MVC REST produces XML on default

I have a problem with Spring MVC and REST. The problem is that when i post a url without extension or whatever extension other then json or html or htm i am always getting an xml response. But i want it to default to text/html response. I was searching in many topics and cant find the answear to this.
Here is my Controller class :
#RequestMapping(value="/user/{username}", method=RequestMethod.GET)
public String showUserDetails(#PathVariable String username, Model model){
model.addAttribute(userManager.getUser(username));
return "userDetails";
}
#RequestMapping(value = "/user/{username}", method = RequestMethod.GET,
produces={"application/xml", "application/json"})
#ResponseStatus(HttpStatus.OK)
public #ResponseBody
User getUser(#PathVariable String username) {
return userManager.getUser(username);
}
Here is my mvc context config:
<mvc:resources mapping="/resources/**"
location="/resources/"/>
<context:component-scan
base-package="com.chodak.controller" />
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="defaultContentType" value="text/html" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json"/>
<entry key="xml" value="application/xml"/>
</map>
</property>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass">
<value>
org.springframework.web.servlet.view.tiles3.TilesView
</value>
</property>
</bean>
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles.xml</value>
</list>
</property>
</bean>
Actually when I tried the built in Eclipse browser it works fine, but when I use firefox or chrome it shows xml response on a request with no extension. I tried using ignoreAcceptHeader, but no change.
Also works on IE :/
If anyone has an idea please help, Thank you.
I actually found out how to do it, i dont really understand why but it is working now, I added default views to the contentresolver like :
<property name="defaultViews">
<list>
<!-- JSON View -->
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
</bean>
<!-- JAXB XML View -->
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.chodak.tx.model.User</value>
</list>
</property>
</bean>
</constructor-arg>
</bean>
</list>
</property>
and removed the getUser method, the one annoted to produce xml and json. If I leave it with the added default views its still not working. If anyone can explain why it would be awesome :)
You can do
import org.springframework.http.MediaType;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
// #EnableWebMvc already autoconfigured by Spring Boot
public class MvcConfiguration {
#Bean
public WebMvcConfigurer contentNegotiationConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false)
.favorParameter(true)
.parameterName("mediaType")
.ignoreAcceptHeader(true)
.useJaf(false)
.defaultContentType(MediaType.APPLICATION_JSON)
.mediaType("xml", MediaType.APPLICATION_XML)
.mediaType("json", MediaType.APPLICATION_JSON);
// this line alone gave me xhtml for some reason
// configurer.defaultContentType(MediaType.APPLICATION_JSON_UTF8);
}
};
}
(tried with Spring Boot 1.5.x)
see https://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc
"What we did, in both cases:
Disabled path extension. Note that favor does not mean use one approach in preference to another, it just enables or disables it. The order of checking is always path extension, parameter, Accept header.
Enable the use of the URL parameter but instead of using the default parameter, format, we will use mediaType instead.
Ignore the Accept header completely. This is often the best approach if most of your clients are actually web-browsers (typically making REST calls via AJAX).
Don't use the JAF, instead specify the media type mappings manually - we only wish to support JSON and XML."

How to use separate realms for authentication and authorization with Shiro and CAS?

I'm working on a web application where multiple applications authenticates through a CAS SSO Server. Howerver, each application should maintain their respective roles and these roles are stored in a database specific to the application. So, I need to have 2 realms, one for CAS (for authc) and another for DB (for authz).
This is my current shiro config. I'm getting the redirection to the CAS working properly, but the logged in user (Subject) doesn't seems to have the roles/permission loaded in it (e.g. SecurityUtil.isPermitted() not working as expected)
<bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
<property name="name" value="jdbcRealm" />
<property name="dataSource" ref="dataSource" />
<property name="authenticationQuery"
value="SELECT password FROM system_user_accounts WHERE username=? and status=10" />
<property name="userRolesQuery"
value="SELECT role_code FROM system_roles r, system_user_accounts u, system_user_roles ur WHERE u.user_id=ur.user_id AND r.role_id=ur.role_id AND u.username=?" />
<property name="permissionsQuery"
value="SELECT code FROM system_roles r, system_permissions p, system_role_permission rp WHERE r.role_id=rp.role_id AND p.permission_id=rp.permission_id AND r.role_code=?" />
<property name="permissionsLookupEnabled" value="true"></property>
<property name="cachingEnabled" value="true" />
<property name="credentialsMatcher" ref="passwordMatcher" />
</bean>
<!-- For CAS -->
<bean id="casRealm" class="org.apache.shiro.cas.CasRealm">
<property name="defaultRoles" value="ROLE_USER" />
<property name="casServerUrlPrefix" value="http://localhost:7080/auth" />
<property name="casService" value="http://localhost:8080/hawk-hck-web/shiro-cas" />
<property name="validationProtocol" value="SAML" />
<property name="cachingEnabled" value="true"></property>
</bean>
<bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory" />
<!-- Security Manager -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realms">
<list>
<ref bean="casRealm" />
<ref bean="jdbcRealm" />
</list>
</property>
<property name="cacheManager" ref="cacheManager"/>
<property name="subjectFactory" ref="casSubjectFactory" />
</bean>
<bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
<property name="failureUrl" value="/error"></property>
</bean>
<!-- Shiro filter -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="http://localhost:7080/auth/login?service=http://localhost:8080/hawk-hck-web/shiro-cas" />
<property name="successUrl" value="/home/index" />
<property name="unauthorizedUrl" value="/error" />
<property name="filters">
<util:map>
<entry key="casFilter" value-ref="casFilter" />
</util:map>
</property>
<property name="filterChainDefinitions">
<value>
<!-- !!! Order matters !!! -->
/shiro-cas = casFilter
/login = anon
/logout = logout
/error = anon
/static/** = anon
/** = authc
</value>
</property>
</bean>
The way I register the realms with the securityManager should be in correct. I can't really find a good example of the setup.
I have 2 questions here:
What is correct setup/configuration to achieve above mentioned scenario?
What is the best practice to manage users and roles across different/seperate applications?
The problem you are running into has to do with the fact that both CasRealm and JdbcRealm extends both AuthorizingRealm (Authorizer) and AuthenticatingRealm. First step I would take is with the JdbcRealm. The JdbcRealm implementation inherits the AuthenticatingRealm#supports(AuthenticationToken token) method implementation. If you extend JdbcRealm and override the "supports" method to return "false" for all token types the JdbcRealm will no longer be used for authentication purposes.
#Override
public boolean supports (AuthenticationToken token) {
return false;
}
The CasRealm is a different story, there is no way (that I know of) to easily tell Shiro to not use a realm that implements Authorizer when checking permissions. I personally find it frustrating that the default implementation for most protocols assumes that both authorization and authentication are needed. I would prefer each to be split into two implementations (eg AuthenticatingCasRealm, AuthorizingCasRealm).
The logic behind checking permissions when multiple realms are in use is documented here. The specific text that references this behavior is:
Step 4: Each configured Realm is checked to see if it implements the
same Authorizer interface. If so, the Realm's own respective hasRole*,
checkRole*, isPermitted*, or checkPermission* method is called.
Based on this, you theoretically could override each of the named methods and all of their overloaded implementations to always return "false".
My solution to this problem is based on my prior comment about splitting each realm into two components, one for authentication and one for authorization. You end up with more duplicate code this way but it is explicit in what behaviors you are expecting from your implementation.
Here's how to go about it:
Create a new class "AuthenticatingCasRealm" that extends org.apache.shiro.realm.AuthenticatingRealm and implements org.apache.shiro.util.Initializable.
Copy and paste the contents of the existing CasRealm source into your new "AuthenticatingCasRealm" class. (I am aware that taking a copy-and-paste route of existing code is often frowned upon however in the described circumstsance I know of no other way of solving the problem.)
Strip out all methods that were implemented for org.apache.shiro.realm.AuthorizingRealm.
Update your Shrio configuration to reference your new AuthenticatingCasRealm implementation.
Based on these changes you should now have two custom implementations in your Shrio config; one of JdbcRealm overriding the "supports" method and one of CasRealm removing the authorization API methods.
There is one additional method based on explicitly declaring an Authorizer via Shiro's configuration that may be better suited to your situation.
Here is an explicit declaration of an Authorizer and Authenticator via a custom ShiroFilter extension. Both were implemented and registered to the provided JNDI names at startup.
public class CustomShiroFilter extends ShiroFilter {
#Override
public void init () throws Exception {
super.init();
DefaultWebSecurityManager dwsm = (DefaultWebSecurityManager) getSecurityManager();
dwsm.setAuthorizer((Authorizer)JndiUtil.get("realms/authorizerRealm"));
dwsm.setAuthenticator((Authenticator)JndiUtil.get("realms/authenticatorRealm"));
}
}
You need only one realm that extends AuthorizingRealm. It will provide
authc: method doGetAuthenticationInfo (CAS server)
authz: method doGetAuthorizationInfo (JDBC)
Hope this helps
We had a similar case where we use a LDAP Realm for authentication and used the standard shiro.ini file for the authorization for a simple use case.
To complement the answer of 'justin.hughey', I give the blueprint (could be spring as well) configuration in order to make your use case working:
<!-- Bean for Authentication -->
<bean id="rccadRealm" class="org.mydomain.myproject.security.shiro.ldap.realm.LdapRealm"
init-method="init">
<property name="searchBase" value="${realm.searchBase}" />
<property name="singleUserFilter" value="${realm.singleUserFilter}" />
<property name="timeout" value="30000" />
<property name="url" value="${contextFactory.url}" />
<property name="systemUsername" value="${contextFactory.systemUsername}" />
<property name="systemPassword" value="${contextFactory.systemPassword}" />
</bean>
<!-- Bean for Authorization -->
<bean id="iniRealm" class="org.mydomain.myproject.security.realm.AuthzOnlyIniRealm">
<argument value="file:$[config.base]/etc/shiro.ini"/>
<property name="authorizationCachingEnabled" value="true" />
</bean>
<bean id="myModularAuthenticator"
class="org.mydomain.myproject.security.service.MyModularRealmAuthenticator">
<property name="realms">
<list>
<ref component-id="ldapRealm" />
</list>
</property>
</bean>
<bean id="mySecurityManager" class="org.apache.shiro.mgt.DefaultSecurityManager">
<property name="authenticator" ref="myModularAuthenticator" />
<property name="authorizer" ref="iniRealm" />
<property name="cacheManager" ref="cacheManager" />
</bean>
The key things is that we needed:
a modularRealmAuthenticator and let the default strategy (as there's only one realm) for the 'authenticator'
a special AuthzOnlyIniRealm which overrides the method supports returning false to prevent using it for authentication.
Our LdapRealm implementation is just an extension of the Shiro ActiveDirectoryRealm.

How to set default method for Delegate method of MultiActionController ?

I'm using Spring MVC for a web app project and I'm trying to avoid using annotations.
I came across as far as getting MultiActionController and delegate working.
The question is, how do I set the default method in the delegate of a MultiActionController ?
By MultiActionController, I mean something like this
public class TestController1 extends MultiActionController{
public TestController1(){
System.out.println("TestController1 initialising...");
}
}
My xml settings are...
<bean id="multiactionController1" class="test.TestController1">
<property name="delegate" ref="testDelegater1"/>
<property name="methodNameResolver" ref="paramResolver"/>
</bean>
<!-- Delegaters -->
<bean id="testDelegater1" class="test.TestController1Delegator"/>
<!-- param method name resolver -->
<bean id="paramResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
<property name="paramName" value="action"/>
</bean>
<!-- Simple Url Handler Mapping -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<map>
<entry key="/multiaction1/**" value-ref="multiactionController1"/>
<entry key="/item/**" value-ref="itemController"/>
</map>
</property>
</bean>
So when I send a request like '*/item' , notice it doesn't have an action parameter, instead of giving me an error I would like to have a default method.
Use following implementation of MethodNameResolver, it has defaultMethodName property.
org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver
I was able to solve this by following instructions in this page.
http://www.cwinters.com/blog/2004/02/18/spring_setting_a_default_action_for_multiactioncontroller.html
As far as I've figured, you need to implement your own MethodNameResolver that returns default method name if no method name has been specified.
I Hope this helps : )

RestClientException Could not extract response spring mvc

i'm trying to connect via the restTemplate to the server side in order to retrieve xml's. But i'm taking an RestClientException and this message:"Could not extract response: no suitable HttpMessageConverter found for response type [frontend.model.Registration] and content type [application/xml]"
In the dispatcher-servlet i write this:
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="xml" value="application/xml"/>
<entry key="atom" value="application/atom+xml"/>
<entry key="html" value="text/html"/>
</map>
</property>
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
</list>
</property>
And afterwards i add this:
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
Also the exception appears at this line:3
ResponseEntity<Registration> result = restTemplate.exchange("http://www.../ckp/user/{id}",
HttpMethod.GET, entity, Registration.class, id);
I can't solve the problem days now..i'm thinking to add ViewResoler and MessageConverter by i don't know which resolvers and which converters. Can anyone propose something to try?
Should i add something on disptcher servlet?should i add a library?
My model classes are pojo's contains jaxb annotations.
You need to add the xml message converter bean to the RestTemplate bean definition. This is what I use:
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</list>
</property>
</bean>
Don't forget to inject the restTemplate bean into your class (via xml or annotation).
EDIT: In your class where you call RestTemplate, add a field like this:
#Inject
private RestTemplate restTemplate;

Resources