REST (Representational State Transfer) is an architecture style that describes how to use HTTP to access web services.
In my previous blog I have explained with example how to create simple RESTful webservice application.
Restful Web Services example using CXF , JAXRS.
This Blog instruction will help us to create a sample secure RESTful webservice using cxf , spring security api and jaxrs api.
NB. I choose spring xml security configuration to secure RESTful webservice application so it will be easy for user to switch on/off and configure security features without modifying service interface and implementation classes. Required Software
Pre-requsite
Instructions assume that jdk,jboss,cxf is installed without any error.
Instructions
Click here to download source code of above example
In my previous blog I have explained with example how to create simple RESTful webservice application.
Restful Web Services example using CXF , JAXRS.
This Blog instruction will help us to create a sample secure RESTful webservice using cxf , spring security api and jaxrs api.
NB. I choose spring xml security configuration to secure RESTful webservice application so it will be easy for user to switch on/off and configure security features without modifying service interface and implementation classes.
- Developemnt
- Eclipse
- CXF 2.5.2
- Spring security api release (version 3.1.3.RELEASE)
- Jboss Application Server 5.0.1 GA
- Testing
- please open existing project that successfully created by using previous blog instructions previous blog instructions . Now we will modify existing project and secure the web application.
- Open web.xml under WEB-INF\web.xml and add following xml snippet.
- Create a new package "com.kaustuv.jaxrs.example.security"
- create a new customize exception class NotAuthorizedException under package "com.kaustuv.jaxrs.example.security". Add following code snippet.
- Create SecurityExceptionMapper under package "com.kaustuv.jaxrs.example.security". Add following code snippet
- Open global-beans.xml under WEB-INF/conf and add bean following line to create SecurityExceptionMapper bean.
- Open jaxrs-beans.xml under WEB-INF/conf and refer exceptionProvider bean information in the jaxrs:providers section along with existing jsonProvider,jaxbXmlProvider,cors-filter
- Create a xml name security-beans.xml under WEB-INF/conf
- Export and package this as war. Destination path %JBOSS_HOME%\server\default
- Open command prompt and go to directory %JBOSS_HOME\bin .
- Execute run.bat -c default -b 0.0.0.0
- click on our wadl url for our restful webservice project. http://localhost:8080/jaxrs-security-example/customerService?_wadl
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name>jaxrs-security-example</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/conf/*beans.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <description>Apache CXF Endpoint</description> <display-name>cxf</display-name> <servlet-name>CXFServlet</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
/** | | Copyright (c) Kaustuv Maji , 2013 | | Please do not use source code in production. | Repos - https://github.com/kaustuvmaji | Blog - http://kaustuvmaji.blogspot.in */ package com.kaustuv.jaxrs.example.security; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.xml.ws.WebFault; /** * @author KMaji * */ @WebFault public class NotAuthorizedException extends WebApplicationException{ private static final long serialVersionUID = -1203116970226591712L; public NotAuthorizedException(String faultString) { super(Response.status(Response.Status.UNAUTHORIZED) .entity(faultString).type(MediaType.TEXT_PLAIN).build()); System.out.println("################NotAuthorizedException(String faultString)######################"); } }
/** | | Copyright (c) Kaustuv Maji , 2014 | | Please do not use source code in production. | Repos - https://github.com/kaustuvmaji | Blog - http://kaustuvmaji.blogspot.in */ package com.kaustuv.jaxrs.example.security; import javax.ws.rs.core.Response; import javax.ws.rs.ext.ExceptionMapper; import javax.ws.rs.ext.Provider; import com.kaustuv.jaxrs.example.security.NotAuthorizedException; /** * * @author kmaji */ @Provider public class SecurityExceptionMapper implements ExceptionMapper{ public Response toResponse(NotAuthorizedException exception) { Response.Status status; // This means that the client could not be authenticated. In this case the client may want to // send (new) credentials and we should return 401. status = Response.Status.UNAUTHORIZED; return Response.status(status).entity(exception.getLocalizedMessage()).build(); } }
<bean id="exceptionProvider" class="com.kaustuv.jaxrs.example.security.SecurityExceptionMapper" />We will use this exceptionProvider bean in our jaxrs server (global) configuration so all services will be able to use this bean.
<?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:jaxrs="http://cxf.apache.org/jaxrs" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:security="http://www.springframework.org/schema/security" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd"> <import resource="classpath:META-INF/cxf/cxf*.xml" /> <!-- Cxf Jason provider --> <bean id="jsonProvider" class="org.apache.cxf.jaxrs.provider.JSONProvider"> <property name="dropRootElement" value="true" /> <property name="supportUnwrapped" value="true" /> </bean> <!-- Cxf Jaxb Provider --> <bean id="jaxbXmlProvider" class="org.apache.cxf.jaxrs.proviacder.JAXBElementProvider" scope="prototype" /> <!-- cxf exception generator --> <bean id="exceptionProvider" class="com.kaustuv.jaxrs.example.security.SecurityExceptionMapper" /> <!-- Cxf Cors filter (cross domain purpose)--> <bean id="cors-filter" class="org.apache.cxf.jaxrs.cors.CrossOriginResourceSharingFilter"/> </beans>
<?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:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:security="http://www.springframework.org/schema/security" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd"> <import resource="classpath:META-INF/cxf/cxf*.xml"/> <!-- Service --> <bean id="customerService" class="com.kaustuv.jaxrs.example.service.DemoCustomerServiceImpl" init-method="init" destroy-method="destroy" /> <!-- Jaxrs Server --> <jaxrs:server id="restserver" address="/customerService"> <!-- adding service bean --> <jaxrs:serviceBeans> <ref bean="customerService" /> </jaxrs:serviceBeans> <!-- adding media type provider --> <jaxrs:providers> <ref bean="jsonProvider" /> <ref bean="jaxbXmlProvider" /> <ref bean="cors-filter" /> <ref bean="exceptionProvider"/> </jaxrs:providers> <jaxrs:features> <cxf:logging/> </jaxrs:features> <!-- Keeping extention type --> <jaxrs:extensionMappings> <entry key="json" value="application/json" /> <entry key="xml" value="application/xml" /> <entry key="html" value="text/html"/> <entry key="feed" value="application/atom+xml"/> </jaxrs:extensionMappings> </jaxrs:server> </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:component-scan base-package="com.kaustuv.jaxrs.example" /> <!-- cxf exception generator --> <beans:bean id="exceptionProvider" class="com.kaustuv.jaxrs.example.security.SecurityExceptionMapper" /> <!-- Authentication manager configuration --> <authentication-manager alias="security"> <authentication-provider> <user-service> <user name="kaustuv" password="kaustuv" authorities="ROLE_ADMIN" /> <user name="get" password="get" authorities="ROLE_GET" /> <user name="post" password="post" authorities="ROLE_POST" /> <user name="put" password="put" authorities="ROLE_PUT" /> <user name="delete" password="delete" authorities="ROLE_DELETE" /> </user-service> </authentication-provider> </authentication-manager> <!-- HTTP basic authentication in Spring Security [option 1] --> <!-- <http> <intercept-url pattern="/customerService/*" access="ROLE_ADMIN" /> <http-basic /> </http> --> <!-- HTTP basic authentication in Spring Security with http intercept url pattern [Option 2] --> <http create-session="stateless" use-expressions="true"> <intercept-url pattern="/customerService/getCustomerById/**" access="hasRole('ROLE_ADMIN')" /> <intercept-url pattern="/customerService/addCustomer/**" access="hasRole('ROLE_POST')" /> <intercept-url pattern="/customerService/updateCustomer/**" access="hasRole('ROLE_PUT')" /> <!-- for multiple authorities use hasAnyRole --> <intercept-url pattern="/customerService/deleteCustomer/**" access="hasAnyRole('ROLE_ADMIN','ROLE_DELETE')" /> <http-basic /> </http> </beans:beans>Now in above xml we are protecting each resource path with the access role. Suppose we want to add customer then we have to use username=post and password=post to add customer otherwise we will not be able to access the resource path. Now carefully look in the authentication manager configuration section, there we configured authorities based on the username and password and in option 2 section we are saying that this path will be access by authenticated users. We can allow anonymous users to access any path by just providing permitAll.
<intercept-url pattern="/" access="permitAll"/>In the above xml there is another section that is option 1. Please note that it is not allowed to keep both option open. Now if we use option 1 then we have to remove or commented out option 2 in the xml then we will uncomment the option 1 section . So by using option 1 each and every methods will be accessible by just providing username=kaustuv and password=kaustuv. In the post developement testing chapter we will the example snippets.
- open soap ui and create a new project using our wadl url. http://localhost:8080/jaxrs-security-example/customerService?_wadl Test HTTP POST Method
- Explore soap ui project name RestCustomerService. Select Request of service addCustoer
- click on auth tab and configure username , password as a new Basic type Authorization . username and password will be post/post.
- enter customer xml use following snippet and click on submit .
- Explore soap ui project name RestCustomerService. Select Request of service updateCustomer
- click on auth tab and configure username , password as a new Basic type Authorization . username and password will be put/put.
- enter customer xml use following snippet and click on submit .
- Explore soap ui project name RestCustomerService. Select Request of service getCustomerById
- click on auth tab and configure username , password as a new Basic type Authorization . username and password will be kaustuv/kaustuv.
- enter value of parameter custId in following example picture value is 2 . click on submit Test HTTP DELETE Method
- Explore soap ui project name RestCustomerService. Select Request of service deleteCustomer
- click on auth tab and configure username , password as a new Basic type Authorization . username and password will be delete/delete.
- enter value of parameter custId in following example picture value is 3 . click on submit .
- Post Development testing
<customer> <customerId>3</customerId> <customerName>testPost</customerName> <phoneNumber>9831098301</phoneNumber> <address> <street>saltlake</street> <city>kolkata</city> <state>westbengal</state> <country>India</country> <pincode>700064</pincode> </address> </customer>
Test HTTP PUT Method
<customer> <customerId>3</customerId> <customerName>testUpdate</customerName> <phoneNumber>9831098301</phoneNumber> <address> <street>saltlake</street> <city>kolkata</city> <state>westbengal</state> <country>India</country> <pincode>700064</pincode> </address> </customer>
Test HTTP GET Method
Click here to download source code of above example
Source Code
- References:
European Union laws require you to give European Union visitors information about cookies used on your blog. In many cases, these laws also require you to obtain consent.
As a courtesy, we have added a notice on your blog to explain Google's use of certain Blogger and Google cookies, including use of Google Analytics and AdSense cookies.
No comments:
Post a Comment