confoo2013 make your java-app rest enabled
TRANSCRIPT
Make your java app REST enabledAnthony Dahanne Confoo 2013 — Feb. 28th, 2013
Confoo 2013
About me …
2
§ Software Engineer at Terracotta– Working on EhCache management REST API and
webapp (aka Terracotta Management Console, TMC)– Strong interest in CI, build tools (maven)– Android developer when time permits ...
Confoo 2013
Terracotta
3
§ Founded 2003 in San Francisco, CA § Joined Software AG in 2011§ Present in India, Europe
and pretty much all over the globe!§ The company behind :
Agenda
§ The Terracotta Management Console example§ Introduction to REST, Java integration
– REST– The Java case : JAX-RS
§ Securing your REST interface– JEE included authc and authz options– Apache Shiro
§ Final words...
2
The Terracotta Management Console example
Terracotta EhCache : Simplified architecture
5
Database
(Web) app
JVM
Business logic
DAO
Terracotta EhCache : Simplified architecture
5
Database
(Web) app
JVM
Business logic
DAO
Terracotta EhCache : Simplified architecture
5
Database
(Web) app
JVM
Business logic
DAO
Terracotta EhCache : Simplified architecture
5
Database
(Web) app
JVM
Business logic
DAO
EhCache
Terracotta EhCache : Simplified architecture
5
Database
(Web) app
JVM
Business logic
DAO
EhCache
Terracotta EhCache : Simplified architecture
5
Database(Web) app
JVM
Business logic
DAO
EhCache
(Web) app
JVM
Business logic
DAO
EhCache
Terracotta EhCache : Simplified architecture
5
Database(Web) app
JVM
Business logic
DAO
EhCache
(Web) app
JVM
Business logic
DAO
EhCache
Terracotta EhCache : Simplified architecture
5
Database(Web) app
JVM
Business logic
DAO
EhCache
(Web) app
JVM
Business logic
DAO
EhCache
Terracotta EhCache : Simplified architecture
5
Database(Web) app
JVM
Business logic
DAO
EhCache
(Web) app
JVM
Business logic
DAO
EhCache
Simplified architecture : management agents
7
(Web) app
JVM
EhCache
Simplified architecture : management agents
7
RestAgent
(Web) app
JVM
EhCache
Simplified architecture : management agents
7
RestAgent
(Web) app
JVM
EhCacheRestAgent
Simplified architecture : management agents
7
RestAgent
(Web) app
JVM
EhCacheRestAgent
Http Client Http Client Terracotta Management Server
Simplified architecture : management agents
7
RestAgent
(Web) app
JVM
EhCacheRestAgent
Http Client Http Client Terracotta Management Server
REST API
Simplified architecture : management agents
7
RestAgent
(Web) app
JVM
EhCacheRestAgent
Http Client Http Client Terracotta Management Server
BrowserJS + CSS
Terracotta Management Console
REST API
Simplified architecture : management agents
7
RestAgent
(Web) app
JVM
EhCacheRestAgent
Http Client Http Client Terracotta Management Server
BrowserJS + CSS
Terracotta Management Console
cURL HTTP Script
REST API
What you can do with the TMC
§ Access your Caches / Cache Managers stats§ Restart a Terracotta server§ Clear a cache§ Dynamically change your Cache / CM config
8
What you can do with the TMC
§ Access your Caches / Cache Managers stats§ Restart a Terracotta server§ Clear a cache§ Dynamically change your Cache / CM config§ Demo !
8
Introduction to REST, Java Integration
A few words about REST…
§ Web services leveraging standard HTTP verbs– GET,POST,PUT,DELETE,OPTIONS,HEAD
§ Conneg (multiple representations)– to negotiate the format (JSON, XML, etc.)
§ Stateless communication§ HATEOAS
10
JAX-RS : Java specification for REST Services
§ Version 1.1 appeared in Java EE 6§ Server only spec (until 2.0, out Q2 2013)§ Annotations driven API§ Oracle / Sun Jersey is the reference impl.
– Redhat Resteasy, Restlet, Apache CXF are among others
11
JAX-RS : Binding your REST services to your app
§ Using web.xml:
13
JAX-RS : Binding your REST services to your app
§ Customizing loading of resources
14
JAX-RS : Annotations available
15
JAX-RS : Annotations available
§ @Provider§ @Path
§ @GET, @PUT, @POST, @DELETE and @HEAD § @Produces
§ @Consumes
15
JAX-RS : Annotations available
§ @Provider§ @Path
§ @GET, @PUT, @POST, @DELETE and @HEAD § @Produces
§ @Consumes
15
@Path(“/cars/{id}”)
JAX-RS : Annotations available
§ @Provider§ @Path
§ @GET, @PUT, @POST, @DELETE and @HEAD § @Produces
§ @Consumes
15
@Path(“/cars/{id}”)
@Produces(“application/json”,”text/plain”)
JAX-RS : Annotations available
§ @Provider§ @Path
§ @GET, @PUT, @POST, @DELETE and @HEAD § @Produces
§ @Consumes
15
@Path(“/cars/{id}”)
@Produces(“application/json”,”text/plain”)
@Consumes(“application/xml”)
JAX-RS : Annotations available to bind parameters
–@PathParam -> path segment.
–@QueryParam -> HTTP query parameter.–@MatrixParam -> HTTP matrix parameter.–@Context ->inject context variables
16
JAX-RS : Annotations available to bind parameters
–@PathParam -> path segment.
–@QueryParam -> HTTP query parameter.–@MatrixParam -> HTTP matrix parameter.–@Context ->inject context variables
16
@GET @Path("/groups/{groupId}") public Collection<Agent> getAgents(@PathParam("groupId") String groupId) { return configSvc.getAgentsByGroup(groupId, authorizer.getPrincipal()); }
JAX-RS : Annotations available to bind parameters
–@PathParam -> path segment.
–@QueryParam -> HTTP query parameter.–@MatrixParam -> HTTP matrix parameter.–@Context ->inject context variables
16
@GET@Produces(MediaType.APPLICATION_JSON)Collection<CacheManagerEntity> getCacheManagers(@Context UriInfo info) { String cacheManagerNames = info.getPathSegments().get(1).getMatrixParameters().getFirst("names"); MultivaluedMap<String, String> qParams = info.getQueryParameters(); List<String> attrs = qParams.get(ATTR_QUERY_KEY);}
@GET @Path("/groups/{groupId}") public Collection<Agent> getAgents(@PathParam("groupId") String groupId) { return configSvc.getAgentsByGroup(groupId, authorizer.getPrincipal()); }
JAX-RS : Raw Content Handlers
§ By default, you can bind your request payload or your response to streams
16
@PUT @Path("/inputstream") @Produces("text/plain") public Response getInputStream(InputStream is) throws IOException { System.out.println(inputStreamToString(is)); return Response.noContent().build(); }
JAX-RS : Raw Content Handlers
§ By default, you can bind your request payload or your response to streams
16
@GET @Path("/outputstream") @Produces("text/plain") public StreamingOutput getOutputStream() { return new StreamingOutput() { @Override public void write(OutputStream output) throws IOException, WebApplicationException { output.write("hello".getBytes()); } }; }
@PUT @Path("/inputstream") @Produces("text/plain") public Response getInputStream(InputStream is) throws IOException { System.out.println(inputStreamToString(is)); return Response.noContent().build(); }
JAX-RS : Adding your own Content Handler
§ Implementing –MessageBodyReader<T> : handle the request–MessageBodyWriter<T> : handle the response
§ Examples : –FileProvider from jersey-core–AbstractJAXBProvider from jersey-core
16
JAX-RS : JAXB Content Handlers
§ Using JAXB you can convert POJOs to XML (or JSON) and vice versa
16
@XmlRootElementpublic final class Agent { private TYPE type; private String name; private String groupId; private String agentLocation; private Integer connectionTimeoutMillis; private Integer readTimeoutMillis; //etc...}
JAX-RS : Meaningful error responses
–Implementing and registering your own ExceptionMapper
@Provider public class DefaultExceptionMapper implements ExceptionMapper<Throwable> { public Response toResponse(Throwable exception) { return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .type(MediaType.APPLICATION_JSON_TYPE) .entity( String.format("{\"error\" : \"%s\" , \"details\" : \"%s\"}", errorMessage, extraErrorMessage)) .build(); } }
16
JAX-RS : Testing anyone ?
§ Integration testing to validate –the REST API–end to end testing
§ How to do integration testing against JAX-RS ?–creating a client and making assertions :
• java.net.HttpUrlConnection, Apache HttpClient–RestAssured from Jayway :
16
expect().statusCode(404).when().get("/cacheManagers/hello");
String expectedResourceLocation = "/api/config/agents/Local Connection 4343";expect().contentType(ContentType.JSON).body(containsString("Local Connection 4343"), containsString("10000")).statusCode(200).when().get(expectedResourceLocation);
Securing your REST interface
Standard JEE security : certificate authentication
§ Basic Authentication§ Form-based login authentication§ Digest Authentication§ SSL Authentication
18
Standard JEE security : basic authentication
GET /private/index.html HTTP/1.1Host: www.example.org
HTTP/1.1 401 Authorization RequiredContent-type: text/htmlWWW-Authenticate: Basic realm="Secured Realm"
18
Standard JEE security : basic authentication
GET /private/index.html HTTP/1.1Host: www.example.org
HTTP/1.1 401 Authorization RequiredContent-type: text/htmlWWW-Authenticate: Basic realm="Secured Realm"
18
If the user is “anthony” and password is “terracotta”, the client sends
GET /private/index.html HTTP/1.1Host: www.example.orgAuthorization: Basic YW50aG9ueTp0ZXJyYWNvdHRh
Since base64(anthony:terracotta) = YW50aG9ueTp0ZXJyYWNvdHRh
Standard JEE security : digest authentication
GET /private/index.html HTTP/1.1Host: www.example.org
HTTP/1.1 401 Authorization RequiredContent-type: text/htmlWWW-Authenticate: Digest realm="MyRealm",qop="auth, auth-int",nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",opaque="5ccc069c403ebaf9f0171e9517f40e41"
18
Standard JEE security : digest authentication
GET /private/index.html HTTP/1.1Host: www.example.org
HTTP/1.1 401 Authorization RequiredContent-type: text/htmlWWW-Authenticate: Digest realm="MyRealm",qop="auth, auth-int",nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",opaque="5ccc069c403ebaf9f0171e9517f40e41"
18
GET /private/index.html HTTP/1.1Host: www.example.orgAuthorization: Digest username="anthony",realm="MyRealm",nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",uri="/private/index.html",qop=auth,nc=00000001,cnonce="0a4f113b",response="6629fae49393a05397450978507c4ef1",opaque="5ccc069c403ebaf9f0171e9517f40e41"
Standard JEE security : digest authentication
GET /private/index.html HTTP/1.1Host: www.example.org
HTTP/1.1 401 Authorization RequiredContent-type: text/htmlWWW-Authenticate: Digest realm="MyRealm",qop="auth, auth-int",nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",opaque="5ccc069c403ebaf9f0171e9517f40e41"
18
GET /private/index.html HTTP/1.1Host: www.example.orgAuthorization: Digest username="anthony",realm="MyRealm",nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",uri="/private/index.html",qop=auth,nc=00000001,cnonce="0a4f113b",response="6629fae49393a05397450978507c4ef1",opaque="5ccc069c403ebaf9f0171e9517f40e41"
Copies
Standard JEE security : digest authentication
GET /private/index.html HTTP/1.1Host: www.example.org
HTTP/1.1 401 Authorization RequiredContent-type: text/htmlWWW-Authenticate: Digest realm="MyRealm",qop="auth, auth-int",nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",opaque="5ccc069c403ebaf9f0171e9517f40e41"
18
GET /private/index.html HTTP/1.1Host: www.example.orgAuthorization: Digest username="anthony",realm="MyRealm",nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",uri="/private/index.html",qop=auth,nc=00000001,cnonce="0a4f113b",response="6629fae49393a05397450978507c4ef1",opaque="5ccc069c403ebaf9f0171e9517f40e41"
Copiescounterrandom
Standard JEE security : digest authentication
GET /private/index.html HTTP/1.1Host: www.example.org
HTTP/1.1 401 Authorization RequiredContent-type: text/htmlWWW-Authenticate: Digest realm="MyRealm",qop="auth, auth-int",nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",opaque="5ccc069c403ebaf9f0171e9517f40e41"
18
GET /private/index.html HTTP/1.1Host: www.example.orgAuthorization: Digest username="anthony",realm="MyRealm",nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",uri="/private/index.html",qop=auth,nc=00000001,cnonce="0a4f113b",response="6629fae49393a05397450978507c4ef1",opaque="5ccc069c403ebaf9f0171e9517f40e41"
Copies
Standard JEE security : digest authentication
GET /private/index.html HTTP/1.1Host: www.example.org
HTTP/1.1 401 Authorization RequiredContent-type: text/htmlWWW-Authenticate: Digest realm="MyRealm",qop="auth, auth-int",nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",opaque="5ccc069c403ebaf9f0171e9517f40e41"
18
GET /private/index.html HTTP/1.1Host: www.example.orgAuthorization: Digest username="anthony",realm="MyRealm",nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",uri="/private/index.html",qop=auth,nc=00000001,cnonce="0a4f113b",response="6629fae49393a05397450978507c4ef1",opaque="5ccc069c403ebaf9f0171e9517f40e41"
Standard JEE security : digest authentication
GET /private/index.html HTTP/1.1Host: www.example.org
HTTP/1.1 401 Authorization RequiredContent-type: text/htmlWWW-Authenticate: Digest realm="MyRealm",qop="auth, auth-int",nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",opaque="5ccc069c403ebaf9f0171e9517f40e41"
18
GET /private/index.html HTTP/1.1Host: www.example.orgAuthorization: Digest username="anthony",realm="MyRealm",nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",uri="/private/index.html",qop=auth,nc=00000001,cnonce="0a4f113b",response="6629fae49393a05397450978507c4ef1",opaque="5ccc069c403ebaf9f0171e9517f40e41"
H1=md5(“anthony:MyRealm:password”)H2=md5(“GET:/private/index.html”)response = md5(“H1:nonce:nc:cnonce:qop:H2)
Standard JEE security : form-based authentication
18
WebappHTTP Client
Standard JEE security : form-based authentication
18
WebappHTTP Client
1. request protected resource
Standard JEE security : form-based authentication
18
WebappHTTP Client
1. request protected resource
2. redirect to the login page
j_usernamej_password
Standard JEE security : form-based authentication
18
WebappHTTP Client
1. request protected resource
j_security_check3. submit login form
2. redirect to the login page
j_usernamej_password
Standard JEE security : form-based authentication
18
WebappHTTP Client
1. request protected resource
j_security_check3. submit login form
4. redirect to the protected resource
Success
2. redirect to the login page
j_usernamej_password
Standard JEE security : form-based authentication
18
WebappHTTP Client
1. request protected resource
j_security_check3. submit login form
4. redirect to the protected resource
Success
2. redirect to the login page
j_usernamej_password
4f. returns error page
Failure
Standard JEE security : certificate authentication
18
Webapp HTTP Client
Success Failure
Keystore Truststore Keystore Truststore
Server.crtServer.crt
Standard JEE security : certificate authentication
18
Webapp HTTP Client
1. request HTTPS protected resource
Success Failure
Keystore Truststore Keystore Truststore
Server.crtServer.crt
Standard JEE security : certificate authentication
18
Webapp HTTP Client
1. request HTTPS protected resource
2. sends cert
Success Failure
Keystore Truststore Keystore Truststore
Server.crtServer.crt
Standard JEE security : certificate authentication
18
Webapp HTTP Client
1. request HTTPS protected resource
2. sends cert
Success Failure
Keystore Truststore Keystore Truststore
Server.crtServer.crt3. sends cert
Client.crtClient.crt
Standard JEE security : certificate authentication
18
Webapp HTTP Client
1. request HTTPS protected resource
2. sends cert
Success Failure
Keystore Truststore Keystore Truststore
Server.crtServer.crt
4. returns protected resource
3. sends certClient.crtClient.crt
Standard JEE security : configuration
19
<security-constraint> <display-name>My security constraint</display-name> <web-resource-collection> <web-resource-name>myresource</web-resource-name> <description/> <url-pattern>/protected/*</url-pattern> </web-resource-collection> <auth-constraint> <description/> <role-name>myuser</role-name> </auth-constraint></security-constraint><login-config> <auth-method>FORM</auth-method> <realm-name>My Realm</realm-name> <form-login-config> <form-login-page>/login.jsp</form-login-page> <form-error-page>/error.jsp</form-error-page> </form-login-config></login-config><security-role> <description/> <role-name>myuser</role-name></security-role>
web.xml
Security with Apache Shiro
§ Shiro is about :– Authentication – Authorization– Realms– Session Management– Cryptography
20
Why choose Shiro over JEE security ?
§ Shiro is deployment agnostic– not necessarily a webapp
§ Shiro secures all the layers of your application– not only the “web layer”
§ Highly customizable– Realms, filters, listeners, etc...
20
Securing your REST application with Shiro
§ Register the Listener and the Filter
–
21
<listener> <listener-class>c.t.m.s.w.s.TMSEnvironmentLoaderListener</listener-class> </listener>
<filter> <filter-name>securityFilter</filter-name> <filter-class>c.t.m.s.w.s.TMSSecurityFilter</filter-class> </filter> <filter-mapping> <filter-name>securityFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> <dispatcher>ERROR</dispatcher> </filter-mapping>
Shiro Realms used
§ For Terracotta REST agents– TCIdentityAssertionRealm
§ For the Terracotta Management Console– TCIniRealm– LdapRealm– ActiveDirectoyRealm
21
Example of shiro.ini
–
21
[main]securityManager = org.apache.shiro.web.mgt.DefaultWebSecurityManagerldapRealm = com.terracotta.management.security.shiro.realm.ActiveDirectoryRealmldapRealm.userDnTemplate = CN={0},CN=Users,DC=mykene,DC=rndlab,DC=locldapRealm.searchBase = DC=mykene,DC=rndlab,DC=locldapRealm.contextFactory.url = ldap://10.21.32.72:389
securityManager.realm = $ldapRealmsecurityManager.sessionManager.globalSessionTimeout = 600000mgmtAuthListener = c.t.m.s.a.ManagementAuthenticationListenersecurityManager.authenticator.authenticationListeners = $mgmtAuthListenerauthc.loginUrl = /login.jspauthc.successUrl = /index.jspiaauthc = com.terracotta.management.security.shiro.web.filter.TCIdentityAssertionFilter
[urls]/login.jsp = authc/logout = logout/** = authc, roles[operator]/rest/** = noSessionCreation, iaauthc, rest[api]
Final words...
Switching to REST for management
§ Brought us :– consumption from outside the Java world– scriptability– “firewalls compatibility”– existing monitoring tools (Nagios, etc...)
18
Lessons learned creating the rest agents ...
18
Lessons learned creating the rest agents ...
§ Prepare for classloading issues– JBoss wants to deploy REST resources using RestEasy– OSGI does not play nice with Jersey resource scanning
18
Lessons learned creating the rest agents ...
§ Prepare for classloading issues– JBoss wants to deploy REST resources using RestEasy– OSGI does not play nice with Jersey resource scanning
§ Be a nice REST citizen– respect the HTTP status codes– return meaningful error responses
18
Lessons learned creating the rest agents ...
§ Prepare for classloading issues– JBoss wants to deploy REST resources using RestEasy– OSGI does not play nice with Jersey resource scanning
§ Be a nice REST citizen– respect the HTTP status codes– return meaningful error responses
18
Lessons learned creating the rest agents ...
§ Prepare for classloading issues– JBoss wants to deploy REST resources using RestEasy– OSGI does not play nice with Jersey resource scanning
§ Be a nice REST citizen– respect the HTTP status codes– return meaningful error responses
§ Security brings complexity
18
Lessons learned creating the rest agents ...
§ Prepare for classloading issues– JBoss wants to deploy REST resources using RestEasy– OSGI does not play nice with Jersey resource scanning
§ Be a nice REST citizen– respect the HTTP status codes– return meaningful error responses
§ Security brings complexity
18
Lessons learned creating the rest agents ...
§ Prepare for classloading issues– JBoss wants to deploy REST resources using RestEasy– OSGI does not play nice with Jersey resource scanning
§ Be a nice REST citizen– respect the HTTP status codes– return meaningful error responses
§ Security brings complexity
§ Ldap has a lot of different schemas ...
18
Useful tools to develop / debug / test
§ Fast deploy your REST based application– Maven jetty:run(ner), or tomcat7:run(ner)– JRebel (not to stop/start your container for every change)
§ Monitor HTTP traffic– Membrane
§ Hand tailor HTTP messages– Curl– Chrome Advanced REST Client (via Chrome Store)
§ Inspect your SSL Keystores and Trustores– Keystore Explorer
18
Useful resources
§ HTTP– Cours du soir, by @paulgreg (en français)
§ REST– Roy Fielding’s thesis
§ JAX-RS / Jersey– RESTful Java, by @patriot1burke– Arun Gupta presentation on JAX-RS 2.0
§ Shiro– Shiro official documentation
18
twitter |email |blog |
terracotta.orgterracotta |
Thank you !
Vote now !https://joind.in/7901