
Secure Restful Web Service using Spring Security Part 2
Posted by johnnyren in Johnny ren's Blog on May 19, 2013 8:31:52 PMWhy Restful?
- Restful is popular alternative to SOAP web service and It is easy to use.
How do you secure your restful web service?
- Because each restful request is a stateless request, so you can’t use standard login page to authenticate a user anymore.
- The solution is to use Http Authentication header, spring security framework.
- I am going to show you how to create your own interceptor to authenticate user requests and use secured annotation to protect your method
Sequence Diagram
- This diagram show Spring Security can protect your Java server side resource.
- The Client makes a request to the server side service.
- YourOwnSecurityInterceptor intercepts the request and extract the Authentication header.
- YourOwnSecurityInterceptor calls AuthercationManger to authticate the user.
- .
YourOwnSecurityInterceptor.java
public class AuthenticationInterceptor extends HandlerInterceptorAdapter {
private AuthenticationManager authenticationManager;
private static final Logger logger = LoggerFactory.getLogger(AuthenticationInterceptor.class);
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
String authorization = request.getHeader("Authorization");
if (authorization == null) {
return false;
}
String[] credentials = decodeHeader(authorization);
assert credentials.length == 2;
Authentication authentication = new UsernamePasswordAuthenticationToken(credentials[0], credentials[1]);
Authentication successfulAuthentication = authenticationManager.authenticate(authentication);
SecurityContextHolder.getContext().setAuthentication(successfulAuthentication);
return true;
}
public String[] decodeHeader(String authorization) {
try {
byte[] decoded = Base64.decode(authorization.substring(6).getBytes("UTF-8"));
String credentials = new String(decoded);
return credentials.split(":");
} catch (UnsupportedEncodingException e) {
throw new UnsupportedOperationException(e);
}
}
…
}
Spring Configuration
- Web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Mvc-dispatcher-servlet.xml
<context:component-scan base-package="com.johnnyweb.stockWatcher.controller" />
<mvc:annotation-driven />
<security:global-method-security secured-annotations="enabled" />
secured-annotations="enabled"
<mvc:interceptors>
<bean id="authenticationInterceptor" class="com.johnnyweb.interceptor.AuthenticationInterceptor">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
</mvc:interceptors>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider>
<security:user-service id="userService">
<security:user name="gwtrest" password="gwtrest" authorities="ROLE_CUSTOMER" />
<security:user name="gwtAdmin" password="gwtAdmin" authorities="ROLE_ADMIN" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
Spring controller
@RequestMapping(method = RequestMethod.GET)
@Secured("ROLE_ADMIN")
public @ResponseBody List<StockPrice> getStocks( @RequestParam(value = "q", required = false) final String q ) {
String[] stockSymbols = q.split(" ");
ArrayList<StockPrice> stockPriceList= new ArrayList<StockPrice>();
for (String stockSymbol : stockSymbols) {
Random rnd = new Random();
double price = rnd.nextDouble() * MAX_PRICE;
double change = price * MAX_PRICE_CHANGE * (rnd.nextDouble() * 2f - 1f);
StockPrice stockPrice = new StockPrice();
stockPrice.setSymbol(stockSymbol);
stockPrice.setPrice(price);
stockPrice.setChange(change);
stockPriceList.add(stockPrice);
}
return stockPriceList;
}
Test your restful service using FIrefox RestClient
http://localhost:8080/SpringMVC/rest/stockWatcher?q=NN
-
SpringRestSecurity.zip 10.1 KB
Comments