Spring security set up access control with oauth2 token - spring-mvc

I am discovering oauth2. I have managed to create a sample which return JWToken and REST protected by this token.
Now i would like to improve this by adding access-control in my protected REST interface.
Why ? Because i would like users like ADMIN, READER access some URL or not.
Following http://projects.spring.io/spring-security-oauth/docs/oauth2.html
it is possible over expression-handler in http node.
Here is the configuration i have added to my xml config :
<sec:global-method-security
pre-post-annotations="enabled" />
<sec:http pattern="/protected/**" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint">
<sec:anonymous enabled="false" />
<sec:intercept-url pattern="/protected/**" />
<sec:custom-filter ref="resourceServerFilter"
before="PRE_AUTH_FILTER" />
<sec:access-denied-handler ref="oauthAccessDeniedHandler" />
<sec:expression-handler ref="myexpressionHandler" />
</sec:http>
<bean id="myexpressionHandler" class="org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandler">
</bean>
log :
févr. 04, 2015 4:09:31 PM org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser parse
INFOS: Expressions were enabled for method security but no SecurityExpressionHandler was configured. All hasPermision() expressions will evaluate to false.
févr. 04, 2015 4:09:31 PM org.springframework.security.config.http.HttpSecurityBeanDefinitionParser checkFilterChainOrder
But with my JWTtoken I successfully get the protected resource.
My controller:
#Component
#RestController
#RequestMapping(value = "/protected")
public class HelloWorldRest {
private static final Logger LOG = LoggerFactory
.getLogger(HelloWorldRest.class);
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
#PreAuthorize("#oauth2.clientHasRole('ROLE_ADMIN')")
#RequestMapping(value = "/greeting/{name}")
public Greeting greeting(#PathVariable String name) {
LOG.info("Fonction greeting : " + name);
return new Greeting(counter.incrementAndGet(), String.format(template,
name + ", I am Mister Toto"));
}
}
I have tested with an user who get authoritiesGrant={ ROLE_NONE }
Thanks,
Any ideas ?

To avoid the error message "SecurityExpressionHandler was configured" you should add the expression handler to your global-method-security. Like this:
<sec:global-method-security pre-post-annotations="enabled">
<sec:expression-handler ref="oauthExpressionHandler" />
</sec:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler" />
Instead of defining your own bean for the WebSecurityExpressionHandler (as you dod in the question) you can additionally use:
<oauth:web-expression-handler id="oauthWebExpressionHandler" />

Related

Content-Type of soap call using spring-integration

I'm trying to execute a soapcall using spring-integration. The WSDL is soap 1.2.
My spring configuration:
<int:channel id="inputChannel" />
<int:channel id="outputChannel" />
<int:header-enricher input-channel="inputChannel" output-channel="outputChannel">
<int:header name="#{T(org.springframework.http.HttpHeaders).CONTENT_TYPE}" value="text/xml" />
</int:header-enricher>
<bean id="eduflexWsTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"
p:marshaller-ref="eduflexMarshaller"
p:unmarshaller-ref="eduflexMarshaller"
p:defaultUri="http://srv-nl-edu65/wsParalax/"
p:messageFactory-ref="soap12MessageFactory"
/>
<bean id="soap12MessageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory">
<property name="soapVersion">
<util:constant static-field="org.springframework.ws.soap.SoapVersion.SOAP_12"/>
</property>
</bean>
Java code:
MyRequestXml request = new MyRequestXml();
//construct request
MyResponse response = (MyResponse) m_template.marshalSendAndReceive(request, new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage message) {
SoapMessage soapMessage = (SoapMessage) message;
soapMessage.setSoapAction("soapAction");
}
});
Initialy the soap action was not set and I got errors about that, so I fixed that by using a WebServiceMessageCallback.
But now I get an error about the content type:
org.springframework.ws.client.WebServiceTransportException: Unsupported Media Type [415]
I'm trying to override it using the spring integration header-enricher, but in wireshark I see that the header content-type is still Multipart/Related.
So my question is how can I force spring integration to set the content type to text/xml? Forcing soap to version 1.2 does not seem to have effect either.
I found out my problem, I had a Jaxb2Marshaller with mtomEnabled set to true.

Session invalidate not working

< ?xml version="1.0" encoding="UTF-8"?>
< beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
< security:global-method-security secured-annotations="enabled" />
< security:http>
< security:intercept-url pattern="/index*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
< security:intercept-url pattern="/login123" access="ROLE_ADMIN" />
< security:intercept-url pattern="/employee1" access="ROLE_EMPLOYEE"/>
< security:intercept-url pattern="/emppreviewshow" access="ROLE_EMPLOYEE"/>
< security:access-denied-handler error-page="/login"/>
<security:form-login login-page="/login" default-target-url="/index"
authentication-failure-url="/fail2login"
username-parameter="username"
password-parameter="j_password" />
<security:session-management invalid-session-url="/logout" session-fixation-protection="newSession" >
<security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</security:session-management>
<security:logout logout-success-url="/logout" delete-cookies="JSESSIONID" invalidate-session="true"/>
</security:http>
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" >
<constructor-arg name="strength" value="255" />
</bean>
<security:authentication-manager>
<security:authentication-provider>
<security:jdbc-user-service data-source-ref="dataSource"
users-by-username-query=
"select username,password, enabled from USER_MASTER where username=?"
authorities-by-username-query=
"select username,USER_ROLE from USER_ROLE where username =? " />
<security:password-encoder ref="passwordEncoder" />
</security:authentication-provider>
</security:authentication-manager>
when i am clicking the logout and when clicking the back button of browser still it is showing the old pages.I want the same login url to be shown when back button is clicked in browser.
you can check the session is active in your all the methods of the controller classes.ie.,request mapped classes,methods.if the session is active then return the page.otherwise redirect to login page.
Welcome to the world of client vs server! Invalidating a session is an on server operation. Assuming that the session id is passed in a cookie, it means that next request containing that cookie will not be member of the previous session, and so you will activate all the "please login first" machinery.
But under normal conditions, hitting the back button on a browser does not send a new request but just display the last page from the local cache. Thus it is a client only operation.
As an application developper, there is little that you can do. You could try to use javascript to hide back button, catch it, or clean the cache. But if I were you, I won't dare to think about that: you are likely to fall in browser compatibiliy problem, for something that you should not care about. What user reads locally is its own problem. If he/she made a printed copy of a page, you would not take a lighter to burn it when the session is over. The cached pages are the same: a local copy. That's the reason why on explicit disconnection you often see a message asking to close the browser window. Itsi the only way for the user to be sure not to read offline copies if he/she click on the back button.
i cannot use the invalidate-session. i just add the "authentication-success-handler-ref" . and set a session inside there.after login the session is set to true.and after logout the sesison is set to false.
this is the code:
Securuty-context.xml
<bean id="customAuthenticationSuccessHandler" class="org.dewbyte.corebank.utility.CustomAuthenticationSuccessHandler"/>
root-context.xml
<bean id="LogoutSuccessHandler" class="org.dewbyte.corebank.utility.LogoutSuccessHandler" />
CustomAuthenticationSuccessHandler class
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler{
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
request.getSession().setAttribute("loginStatus", "true");
String targetUrl = "/dashboard";
redirectStrategy.sendRedirect(request, response, targetUrl);
}
public RedirectStrategy getRedirectStrategy() {
return redirectStrategy;
}
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
}
LogoutSuccessHandler class
public class LogoutSuccessHandler implements org.springframework.security.web.authentication.logout.LogoutSuccessHandler{
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
public RedirectStrategy getRedirectStrategy() {
return redirectStrategy;
}
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
#Override
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
request.getSession().setAttribute("loginStatus", "false");
String targetUrl = "/";
redirectStrategy.sendRedirect(request, response, targetUrl);
}
}
check the session is true or false in every methods in the controller classes.
Controller class
if (request.getSession().getAttribute("loginStatus").equals("true"))
{
return home;
}
else
return login;

my ConversionService encountered 500 error code

I am learning the spring mvc and when i try to use the ConversionService ,i encounterrd 500
#RequestMapping("/handle81")
public String handle81(#RequestParam("user")User user,ModelMap modelMap) {
System.out.println(user);
modelMap.put("user", user);
return "/user/success";
}
this is the handler method ,i've put the #RequestMapping("/user") at the class
and the converter
public class StringToUserConverter implements Converter<String, User> {
public User convert(String source) {
System.out.println(source);
User user=new User();
String[] item=source.split(":");
user.setUserName(item[0]);
user.setPassword(item[1]);
user.setName(item[2]);
return user;
}
}
<mvc:annotation-driven conversion-service="conversionService" />
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.baobaotao.domain.StringToUserConverter" />
</list>
</property>
</bean>
so when i browse
http://localhost:8080/spring-mvc/user/handle81.html?user=asdf:asdf:fdas
it gets 500 and prints nothing at the console(i use maven-jetty to do the test)
thx for helping~
I think your Request URL may not be not matching. You specify "/handle81" in the annotation, but are requesting "/handle81.html".
It's hard to tell, without further information, whether the problem is matching & dispatching the request to the handler; or in the conversion.
Try another handler with the parameter of type String, and see whether you can call that successfully. At least you'll then know where the problem is.
And what is the exception stack-trace? Why didn't you post it? That's your most important clue & you should always post the ex message & top few lines/ where it was thrown, when you ask a question. It should be in either the application or Tomcat/ other server logs.

Spring Security 2.0.6 what calls the loadUserByName method of an UserDetailService

I'm building a simple Sring MVC app. And now i'm trying to add Spring security. I've added a customUserDetailsService that uses a DAO to access a MySql database and get users.
#Transactional(readOnly = true)
public class CustomUserDetailService implements UserDetailsService {
#EJB(name = "UserDAOLocal")
UserDAOLocal dao = null;
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
System.out.println("Checking if this is invoked")
UserDetails user = null;
DBUsers dbUser = dao.findUserName(username);
user = new User(dbUser.getUserName(), dbUser.getPassword(), true, true, true, true, getAuthorities(dbUser.getAccess()));
return user;
}
private GrantedAuthority[] getAuthorities(Integer access) {
GrantedAuthority[] authList = new GrantedAuthority[2];
authList[0] = new GrantedAuthorityImpl("ROLE_USER");
if (access.compareTo(1) == 0) {
authList[1] = new GrantedAuthorityImpl(("ROLE_ADMIN"));
}
return authList;
}
}
And i've added the UserDetailsService to the Spring-security.xml.
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="customUserDetailsService"/>
</security:authentication-manager>
<bean id="customUserDetailsService" class="service.CustomUserDetailService"/>
I put j_spring_security_check as the action to the login form on the login.jsp page.
When i enter a valid username and a password the app always tells it's wrong. What's more is i can't find any evidence that the customUserDetailsService is running at anytime. (I used System.out.println("Checking if this is invoked") to check on the server).
What invokes the loadUserByUsername() method of the CustomUserDetailsService? When is it invoked?
How can i configure it?
(All the codes i supplied might be unnecessary :))
EDIT:
Here is the rest of the Spring-Security.xml
<security:http auto-config="true">
<security:intercept-url pattern="/AddEmployee.htm" access="ROLE_ADMIN"/>
<security:intercept-url pattern="/FireEmployee.htm" access="ROLE_ADMIN"/>
<security:intercept-url pattern="/employees.htm" access="ROLE_USER"/>
<security:form-login login-page="/login.htm"
authentication-failure-url="/login.htm?error=true"
login-processing-url="/j_spring_security_check.htm"
default-target-url="/common.htm"/>
<security:logout
invalidate-session="true"
logout-success-url="/login.htm"
logout-url="/logout.htm"/>
</security:http>
I worked around the problem by editing the authentication provider like this. I decided not use DAO, and user database. and used hard coded users inside the xml file
<security:authentication-provider>
<security:user-service>
<security:user name="sam" password="sam123" authorities="ROLE_ADMIN,ROLE_USER" />
<security:user name="pam" password="pam123" authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider>
This works perfectly.
But i would like to know why my customUserDetailService was never used, And learn how to use it correctly.
Sharing more config. from Spring-security.xml would help(if possible)
Spring security is Designed so that your Authentication provider calls loadUserByUsername() method of the UserDetailsService which returns userDetails Object.
Process is as follows:
Task of Authentication Manager is to Authenticate the user. So it sends the user name to Authentication provider.
Authentication Provider calls loadUserByUsername() method and passes user name of type String which returns userDetails Object.
Now this userDetails object contains all necessary information for authentication, such as username, password, isEnabled etc.
Now if you want to customize userDetailsService for using your Dao you can customize it.
This is how your authentication process works.
You can refer this link for broader understanding.

Basic Auth for WSO2 EI API service

I am using WSO2-EI 6.4.0. I have tried this development with link. It work for me. But I need to get user name and password from other back end service. In this example was showed the hard corded user and password. I have added that code for your reference. Please help me to get those user name and password from property file.
public boolean processSecurity(String credentials) {
String decodedCredentials = new String(new Base64().decode(credentials.getBytes()));
String usernName = decodedCredentials.split(":")[0];
String password = decodedCredentials.split(":")[1];
if ("admin".equals(username) && "admin".equals(password)) {
return true;
} else {
return false;
}
}
I have added WSO2 EI handler like following. I need to pass the value from back service or call other sequence and load.
<api context="/test">
<resource methods="POST">
<inSequence>
................
</inSequence>
<outSequence>
................
</outSequence>
</resource>
<handlers>
<handler class="rezg.ride.common.BasicAuthHandler">
<property name="cm_password" value="admin"/>
<property name="cm_userName" value="admin"/>
</handler>
</handlers>
</api>
When we run the above API, handlers are running first and then running in and out sequences. So I need to get user name and password calling Sequence or any other method before run this BasicAuthHandler.
If you need to read the property file from the class mediator it's just straight forward java property file reading. Please refer the following call sample of reading a property file. In this scenario, Just read the carbon.properties file exists in the conf directory.
public boolean mediate(MessageContext context) {
String passwordFileLocation = System.getProperty("conf.location")+"/carbon.properties";
try (FileInputStream input = new FileInputStream(passwordFileLocation)) {
Properties prop = new Properties();
// load a properties file
prop.load(input);
log.info("------org.wso2.CipherTransformation : " + prop.getProperty("org.wso2.CipherTransformation"));
} catch (IOException ex) {
ex.printStackTrace();
}
return true;
}
To get the server location and the conf locating, There are JAVA system properties are set at the time wso2 server starts. Following are some of the useful System system properties.
carbon.local.ip
carbon.home
conf.location

Resources