- 浏览: 91522 次
- 性别:
- 来自: 南京
文章分类
最新评论
-
空杯V:
尽管解决了初步问题 但是第三步安装时还是会因为权限问题二不能安 ...
Checking operating system version: must be 4.0, 5.0, 5.1 or 5.2. Actual 6.1 -
wanghaoran04141205:
嗯,不错,我试过了,很好用
URLEncoder.encode时空格变成加号(+) -
qepwqnp:
zzknight 写道大侠 ,那万一文件名是 “新建+文本文 ...
URLEncoder.encode时空格变成加号(+) -
zzknight:
大侠 ,那万一文件名是 “新建+文本文档.txt” 呢?
URLEncoder.encode时空格变成加号(+) -
jainoo00oo:
很有用啊,谢谢
Checking operating system version: must be 4.0, 5.0, 5.1 or 5.2. Actual 6.1
SSL enabled RESTful services are quite easier to develop and test using Jersey, Grizzly and RestTemplate.
Jersey (resource development)
Grizzly Web Server (resource configuration and deployment)
Spring 3 RestTemplate backed by Commons HTTP Client (resource access)
In a moment, you will notice how all these nicely fit the bill. Let us start with the POM for the maven fans.
< dependencies >
< dependency >
< groupId >org.springframework</ groupId >
< artifactId >org.springframework.web</ artifactId >
< version >3.0.0.M4</ version >
</ dependency >
< dependency >
< groupId >commons-httpclient</ groupId >
< artifactId >commons-httpclient</ artifactId >
< version >3.1</ version >
</ dependency >
< dependency >
< groupId >com.sun.jersey</ groupId >
< artifactId >jersey-server</ artifactId >
< version >1.1.2-ea</ version >
</ dependency >
< dependency >
< groupId >com.sun.grizzly</ groupId >
< artifactId >grizzly-servlet-webserver</ artifactId >
< version >1.9.18a</ version >
</ dependency >
< dependency >
< groupId >org.apache.log4j</ groupId >
< artifactId >com.springsource.org.apache.log4j</ artifactId >
< version >1.2.15</ version >
</ dependency >
</ dependencies >
|
Configuring Log4j is very useful as you could see the commons Client debug messages and http wire headers which are quite useful for debugging in case if you were lost in translation.
Putting together all these pieces working did not take much of my time. I did not have to do anything fancy here as I just reused most of the sample code from the Jersey HTTPS sample and Commons HTTP Client SSL sample.
Lets dive into the Spring Config, which does most of the wiring of HTTP Client and RestTemplate.
<? xml version = "1.0" encoding = "UTF-8" ?>
xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" >
< bean id = "sslClient" class = "spring3.restclient.RestSSLClient" >
< constructor-arg ref = "restTemplate" />
< constructor-arg ref = "credentials" />
</ bean >
< bean id = "httpClientParams" class = "org.apache.commons.httpclient.params.HttpClientParams" >
< property name = "authenticationPreemptive" value = "true" />
< property name = "connectionManagerClass"
value = "org.apache.commons.httpclient.MultiThreadedHttpConnectionManager" />
</ bean >
< bean id = "httpClient" class = "org.apache.commons.httpclient.HttpClient" >
< constructor-arg ref = "httpClientParams" />
</ bean >
< bean id = "credentials" class = "org.apache.commons.httpclient.UsernamePasswordCredentials" >
< constructor-arg value = "admin" />
< constructor-arg value = "adminadmin" />
</ bean >
< bean id = "httpClientFactory" class = "org.springframework.http.client.CommonsClientHttpRequestFactory" >
< constructor-arg ref = "httpClient" />
</ bean >
< bean id = "restTemplate" class = "org.springframework.web.client.RestTemplate" >
< constructor-arg ref = "httpClientFactory" />
< property name = "messageConverters" >
< list >
< bean class = "org.springframework.http.converter.StringHttpMessageConverter" />
</ list >
</ property >
</ bean >
</ beans >
|
The below code configures a Grizzly Server with SSL support for server side certificates, Basic Auth filter and Jersey resource servlet.
import com.sun.grizzly.SSLConfig;
import com.sun.grizzly.http.embed.GrizzlyWebServer;
import com.sun.grizzly.http.servlet.ServletAdapter;
import com.sun.jersey.api.container.filter.RolesAllowedResourceFilterFactory;
import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.spi.container.servlet.ServletContainer;
import com.sun.jersey.samples.https_grizzly.auth.SecurityFilter;
import javax.ws.rs.core.UriBuilder;
import java.io.IOException;
import java.net.URI;
public class GrizzlyServer {
private static GrizzlyWebServer webServer;
public static final URI BASE_URI = getBaseURI();
private static URI getBaseURI() {
}
private static int getPort( int defaultPort) {
String port = System.getenv( "JERSEY_HTTP_PORT" );
if ( null != port) {
try {
return Integer.parseInt(port);
} catch (NumberFormatException e) {
}
}
return defaultPort;
}
protected static void startServer() {
webServer = new GrizzlyWebServer(getPort( 4463 ), "." , true );
// add Jersey resource servlet
ServletAdapter jerseyAdapter = new ServletAdapter();
jerseyAdapter.addInitParameter( "com.sun.jersey.config.property.packages" , "server.https.auth;server.https.resource" );
jerseyAdapter.setContextPath( "/" );
jerseyAdapter.setServletInstance( new ServletContainer());
// add security filter (which handles http basic authentication)
jerseyAdapter.addInitParameter(ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS, SecurityFilter. class .getName());
// add authorization filter
jerseyAdapter.addInitParameter(ResourceConfig.PROPERTY_RESOURCE_FILTER_FACTORIES, RolesAllowedResourceFilterFactory. class .getName());
webServer.addGrizzlyAdapter(jerseyAdapter, new String[]{ "/" });
// Grizzly ssl configuration
SSLConfig sslConfig = new SSLConfig();
sslConfig.setNeedClientAuth( true ); // don't work - known grizzly bug, will be fixed in 2.0.0
// set up security context
String keystore_server = Thread.currentThread().getContextClassLoader().getResource( "keystore_server" ).getFile();
String truststore_server = Thread.currentThread().getContextClassLoader().getResource( "truststore_server" ).getFile();
sslConfig.setKeyStoreFile(keystore_server); // contains server keypair
sslConfig.setKeyStorePass( "secret" );
sslConfig.setTrustStoreFile(truststore_server); // contains client certificate
sslConfig.setTrustStorePass( "secret" );
webServer.setSSLConfig(sslConfig);
// turn server side client certificate authentication on
// ((SSLSelectorThread) webServer.getSelectorThread()).setNeedClientAuth(true); try {
// start Grizzly embedded server //
System.out.println(String.format( "Jersey app started with WADL at %sapplication.wadl" , BASE_URI));
webServer.start();
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
protected static void stopServer() {
webServer.stop();
}
public static void main(String[] args) throws InterruptedException, IOException {
startServer();
System.out.println( "Hit return to stop..." );
System.in.read();
stopServer();
}
} |
Here’s slightly modified version of the sample Jersey Security filter which would handle the HTTP basic authentication on the server. The auth helper classes (AuthenticationExceptionMapper, AuthenticationException) are found here.
package com.sun.jersey.samples.https_grizzly.auth;
import com.sun.jersey.api.container.MappableContainerException;
import com.sun.jersey.core.util.Base64;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerRequestFilter;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import java.security.Principal;
public class SecurityFilter implements ContainerRequestFilter {
@Context
UriInfo uriInfo;
private static final String REALM = "HTTPS Example authentication" ;
public ContainerRequest filter(ContainerRequest request) {
User user = authenticate(request);
request.setSecurityContext( new Authorizer(user));
return request;
}
private User authenticate(ContainerRequest request) {
// Extract authentication credentials
String authentication = request.getHeaderValue(ContainerRequest.AUTHORIZATION);
if (authentication == null ) {
throw new MappableContainerException
( new AuthenticationException( "Authentication credentials are required" , REALM));
}
if (!authentication.startsWith( "Basic " )) {
return null ;
// additional checks should be done here
// "Only HTTP Basic authentication is supported"
}
authentication = authentication.substring( "Basic " .length());
String[] values = new String(Base64.base64Decode(authentication)).split( ":" );
if (values.length < 2 ) {
throw new WebApplicationException( 400 );
// "Invalid syntax for username and password"
}
String username = values[ 0 ];
String password = values[ 1 ];
if ((username == null ) || (password == null )) {
throw new WebApplicationException( 400 );
// "Missing username or password"
}
// Validate the extracted credentials
User user = null ;
if (username.equals( "john" ) && password.equals( "secret" )) {
user = new User( "john" , "user" );
System.out.println( "USER 'John Doe' AUTHENTICATED" );
} else if (username.equals( "jane" ) && password.equals( "secret" )) {
user = new User( "jane" , "user" );
System.out.println( "USER 'Jane Doe' AUTHENTICATED" );
} else if (username.equals( "admin" ) && password.equals( "adminadmin" )) {
user = new User( "admin" , "admin" );
System.out.println( "ADMIN AUTHENTICATED" );
} else {
System.out.println( "USER NOT AUTHENTICATED" );
throw new MappableContainerException( new AuthenticationException( "Invalid username or password\r\n" , REALM));
}
return user;
}
public class Authorizer implements SecurityContext {
private User user;
private Principal principal;
public Authorizer( final User user) {
this .user = user;
this .principal = new Principal() {
public String getName() {
return user.username;
}
};
}
public Principal getUserPrincipal() {
return this .principal;
}
public boolean isUserInRole(String role) {
return (role.equals(user.role));
}
public boolean isSecure() {
return "https" .equals(uriInfo.getRequestUri().getScheme());
}
public String getAuthenticationScheme() {
return SecurityContext.BASIC_AUTH;
}
}
public class User {
public String username;
public String role;
public User(String username, String role) {
this .username = username;
this .role = role;
}
}
} |
The resource class is very simple. The resource methods are access controlled using the JSR-250 annotation @RolesAllowed. The methods are self-explanatory and they are just coded for illustration, not a fool-proof implementation. In this sample, the Grizzly server would perform server-side certificate authentication and HTTP Basic authentication, in addition to basic authorization checks.
import com.sun.jersey.core.util.Base64;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@Path ( "/" )
public class HttpsResource {
@GET
@RolesAllowed ({ "admin" })
@Path ( "/locate/{username}" )
public Response getUserLocation( @Context HttpHeaders headers, @PathParam ( "username" ) String username) {
// you can get username from HttpHeaders
System.out.println( "Service: GET / User Location for : " + username + " requested by " + getUser(headers));
return Response.ok( "Billings, Montana" ).type(MediaType.TEXT_PLAIN).build();
}
@GET
@RolesAllowed ({ "admin" , "user" })
public Response getUserPin( @Context HttpHeaders headers) {
// you can get username from HttpHeaders
System.out.println( "Service: GET / User Pin for: " + getUser(headers));
return Response.ok( "1234" ).type(MediaType.TEXT_PLAIN).build();
}
private String getUser(HttpHeaders headers) {
String auth = headers.getRequestHeader( "authorization" ).get( 0 );
auth = auth.substring( "Basic " .length());
String[] values = new String(Base64.base64Decode(auth)).split( ":" );
String username = values[ 0 ];
String password = values[ 1 ];
return username;
}
} |
The following steps guide to create sample client and server certificates using the JDK keytool utility. The self-signed certificates are used for demonstration purposes only. In reality, this would be performed by a Certificate Authority (for ex: Verisign).
-
generate client and server keys:
keytool -genkey -keystore keystore_client -alias clientKey -dname “CN=www.aruld.info, OU=R&D, O=Vasun Technologies, L=Billings, ST=Montana, C=US”
keytool -genkey -keystore keystore_server -alias serverKey -dname “CN=www.aruld.info, OU=R&D, O=Vasun Technologies, L=Billings, ST=Montana, C=US”
-
generate client and server certificates:
keytool -export -alias clientKey -rfc -keystore keystore_client > client.cert
keytool -export -alias serverKey -rfc -keystore keystore_server > server.cert
-
import certificates to corresponding truststores:
keytool -import -alias clientCert -file client.cert -keystore truststore_server
keytool -import -alias serverCert -file server.cert -keystore truststore_client
SSL helper classes (AuthSSLProtocolSocketFactory, AuthSSLX509TrustManager, AuthSSLInitializationError) for the client-side are used from the Commons Client SSL contrib samples.
RestTemplate is injected into the RestSSLClient which uses the Commons Client APIs to set the credentials and configures the keystore and truststore on the client-side.
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.contrib.ssl.AuthSSLProtocolSocketFactory;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.springframework.http.client.CommonsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.HashMap;
public class RestSSLClient {
private final RestTemplate restTemplate;
private final HttpClient client;
private Credentials credentials;
private static final int HTTPS_PORT = 4463 ;
private static final String HTTPS = "https" ;
private static final String HTTPS_HOST = "localhost" ;
public RestSSLClient(RestTemplate restTemplate, Credentials credentials) {
this .restTemplate = restTemplate;
this .credentials = credentials;
CommonsClientHttpRequestFactory factory = (CommonsClientHttpRequestFactory) restTemplate.getRequestFactory();
this .client = factory.getHttpClient();
client.getState().setCredentials(AuthScope.ANY, credentials);
try {
URL keystore_client = Thread.currentThread().getContextClassLoader().getResource( "keystore_client" ).toURI().toURL();
URL truststore_client = Thread.currentThread().getContextClassLoader().getResource( "truststore_client" ).toURI().toURL();
ProtocolSocketFactory protocolSocketFactory = new AuthSSLProtocolSocketFactory(keystore_client, "secret" ,
truststore_client, "secret" );
Protocol authhttps = new Protocol(HTTPS, protocolSocketFactory, HTTPS_PORT);
Protocol.registerProtocol(HTTPS, authhttps);
client.getHostConfiguration().setHost(HTTPS_HOST, HTTPS_PORT, authhttps);
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
public void setCredentials(String user, String pass) {
this .credentials = new UsernamePasswordCredentials(user, pass);
client.getState().setCredentials(AuthScope.ANY, credentials);
}
public String get() {
return restTemplate.getForObject(HTTPS_GET, String. class );
}
public String getLocation(String user) {
Map<String, String> vars = new HashMap<String, String>();
vars.put( "username" , user);
return restTemplate.getForObject(HTTPS_GET_LOCATION, String. class , vars);
}
} |
The test code which invokes the SSL configured resource is shown below.
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Spring3RestSSLClient {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "applicationContext-ssl.xml" );
RestSSLClient client = applicationContext.getBean( "sslClient" , RestSSLClient. class );
System.out.println( "John's Location : " + client.getLocation( "john" ));
System.out.println( "Jane's Location : " + client.getLocation( "jane" ));
client.setCredentials( "john" , "secret" );
System.out.println( "John Doe's Pin : " + client.get());
client.setCredentials( "jane" , "secret" );
System.out.println( "Jane Doe's Pin : " + client.get());
}
} |
WADL for this resource can be accessed from https://localhost:4463/application.wadl. You could access the URL from a browser as the server side client certificate authentication is disabled in the GrizzlyServer. (Uncommenting line # 70 would enable server side client cert auth, but this would force the browser to use the generated client keys). Test it yourself, you would be presented with a basic auth dialog (valid user/pass/role: admin/adminadmin/admin, john/secret/user, jane/secret/user) and you could access the resource methods with specified roles. I have tested with Firefox and Chrome. Enjoy!
相关推荐
"Accessing Web Services from a Visual Web Application"这一主题主要关注如何在基于Visual Web的应用程序中集成Web服务。Visual Web工具通常提供了直观的界面,使开发者能够轻松地连接到Web服务并使用它们的功能。...
* ra_svn : Module for accessing a repository using the svn network protocol. - with Cyrus SASL authentication - handles 'svn' scheme * ra_local : Module for accessing a repository on local disk. - ...
Fluent 系列软件提供了一系列预先设计的方程来从求解器中读写数据。这些方程以宏的形式存放在代码中。这章的所列出的宏是被定义在扩展名为.h文件里的。例如mem.h, metric.h, 和dpm.h。在udf.h文件中包含了宏的定义和...
Reimagined for full-screen and touch-optimized apps, Windows 8 provides a ... accessing web services, calling Win32 and DirectX functions, and bringing your application to the Windows 8 app store.
How to use RESTful services with Swift How to create a complete app with Swift and HealthKit Who this book is for Beginning to intermediate iOS and OS X developers who need to learn Swift or migrate ...
Chapter 13: Building RESTful Web Services with JAX-RS 219 What Are RESTful Web Services? 219 Creating a RESTful Root Resource Class 220 Example Applications for JAX-RS 235 Further Information ...
33. Calling REST Services with RestTemplate 33.1. RestTemplate Customization 34. Calling REST Services with WebClient 34.1. WebClient Customization 35. Validation 36. Sending Email 37. Distributed ...
访问属性 访问属性 (Accessing Properties)(Accessing Properties) (Accessing Properties) (Accessing Properties) (Accessing Properties)(Accessing Properties) (Accessing Properties)(Accessing Properties)...
WebAssembly: Accessing C and C++ in Web Applications English | MP4 | AVC 1280×720 | AAC 48KHz 2ch | 1h 45m | 213 MB Accelerate web applications with native code using WebAssembly. WebAssembly is a ...
MCTS Self-Paced Training Kit (Exam 70-516) Accessing Data with Microsoft .NET Framework 4 eBook.pdf.7z. 請用7zip解壓
MCTS 70-516 Accessing Data with Microsoft .NET Framework 4 练习1。注意,因为我只能上传小于15兆的文件,所以我把setup1.msi给那出去了。安装时需要把setup1.exe放进Practice Tests文件夹。
4. WCF Data Services (OData):这是一种基于开放数据协议(OData)的服务,用于创建和消费RESTful数据服务。在.NET 4中,开发者可以使用WCF Data Services来暴露和访问关系数据库、XML文档、甚至是其他OData服务的...
Using location-related services such as the Google Maps API Building faster applications with native code Providing backup and restore with the Android Backup Manager Testing and debugging apps ...
Tomorrow's mobile applications must be smarter than ever, accessing and intelligently using a wide range of location data. In Mobile Location Services, leading mobile application consultant Andrew ...
15.3. Exposing remote services with Hessian and Burlap 15.3.1. Exposing bean functionality with Hessian/Burlap 15.3.2. Accessing Hessian/Burlap services 15.4. Using Spring’s HttpInvoker 15.4.1. ...
Develop RESTful API applications for XML and JSON data transfers with non-blocking asynchronous capabilities Explore Spring's comprehensive transaction support for declarative Transaction Management ...
P2P Services with Google Talk 7 Extensive Media Support and 2D/3D Graphics 8 Optimized Memory and Process Management 8 Introducing the Open Handset Alliance 8 What Does Android Run On? 9 Why ...