diff --git a/spring-security-rest-digest-auth/src/main/java/org/baeldung/client/ClientPreemptiveDigestAuthentication.java b/spring-security-rest-digest-auth/src/main/java/org/baeldung/client/ClientPreemptiveDigestAuthentication.java new file mode 100644 index 0000000000..5887d2dcab --- /dev/null +++ b/spring-security-rest-digest-auth/src/main/java/org/baeldung/client/ClientPreemptiveDigestAuthentication.java @@ -0,0 +1,70 @@ +package org.baeldung.client; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.AuthCache; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.protocol.ClientContext; +import org.apache.http.impl.auth.DigestScheme; +import org.apache.http.impl.client.BasicAuthCache; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.util.EntityUtils; + +/** + * An example of HttpClient can be customized to authenticate + * preemptively using DIGEST scheme. + * + * Generally, preemptive authentication can be considered less + * secure than a response to an authentication challenge + * and therefore discouraged. + */ +public class ClientPreemptiveDigestAuthentication { + + public static void main(final String[] args) throws Exception { + final HttpHost targetHost = new HttpHost("localhost", 8080, "http"); + + final DefaultHttpClient httpclient = new DefaultHttpClient(); + try { + httpclient.getCredentialsProvider().setCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()), new UsernamePasswordCredentials("user1", "user1Pass")); + + // Create AuthCache instance + final AuthCache authCache = new BasicAuthCache(); + // Generate DIGEST scheme object, initialize it and add it to the local auth cache + final DigestScheme digestAuth = new DigestScheme(); + // Suppose we already know the realm name + digestAuth.overrideParamter("realm", "Custom Realm Name"); + + // digestAuth.overrideParamter("nonce", "whatever"); + authCache.put(targetHost, digestAuth); + + // Add AuthCache to the execution context + final BasicHttpContext localcontext = new BasicHttpContext(); + localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache); + + final HttpGet httpget = new HttpGet("http://localhost:8080/spring-security-rest-digest-auth/api/foos/1"); + + System.out.println("executing request: " + httpget.getRequestLine()); + System.out.println("to target: " + targetHost); + + for (int i = 0; i < 3; i++) { + final HttpResponse response = httpclient.execute(targetHost, httpget, localcontext); + final HttpEntity entity = response.getEntity(); + + System.out.println("----------------------------------------"); + System.out.println(response.getStatusLine()); + if (entity != null) { + System.out.println("Response content length: " + entity.getContentLength()); + } + EntityUtils.consume(entity); + } + } finally { + // When HttpClient instance is no longer needed, shut down the connection manager to ensure immediate deallocation of all system resources + httpclient.getConnectionManager().shutdown(); + } + } + +} diff --git a/spring-security-rest-digest-auth/src/main/java/org/baeldung/client/HttpComponentsClientHttpRequestFactoryBasicAuth.java b/spring-security-rest-digest-auth/src/main/java/org/baeldung/client/HttpComponentsClientHttpRequestFactoryDigestAuth.java similarity index 61% rename from spring-security-rest-digest-auth/src/main/java/org/baeldung/client/HttpComponentsClientHttpRequestFactoryBasicAuth.java rename to spring-security-rest-digest-auth/src/main/java/org/baeldung/client/HttpComponentsClientHttpRequestFactoryDigestAuth.java index 5f808413ce..d9d89db224 100644 --- a/spring-security-rest-digest-auth/src/main/java/org/baeldung/client/HttpComponentsClientHttpRequestFactoryBasicAuth.java +++ b/spring-security-rest-digest-auth/src/main/java/org/baeldung/client/HttpComponentsClientHttpRequestFactoryDigestAuth.java @@ -5,17 +5,17 @@ import java.net.URI; import org.apache.http.HttpHost; import org.apache.http.client.AuthCache; import org.apache.http.client.protocol.ClientContext; -import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.auth.DigestScheme; import org.apache.http.impl.client.BasicAuthCache; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; import org.springframework.http.HttpMethod; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -public class HttpComponentsClientHttpRequestFactoryBasicAuth extends HttpComponentsClientHttpRequestFactory { +public class HttpComponentsClientHttpRequestFactoryDigestAuth extends HttpComponentsClientHttpRequestFactory { HttpHost host; - public HttpComponentsClientHttpRequestFactoryBasicAuth(final HttpHost host) { + public HttpComponentsClientHttpRequestFactoryDigestAuth(final HttpHost host) { super(); this.host = host; } @@ -30,9 +30,14 @@ public class HttpComponentsClientHttpRequestFactoryBasicAuth extends HttpCompone private HttpContext createHttpContext() { // Create AuthCache instance final AuthCache authCache = new BasicAuthCache(); - // Generate BASIC scheme object and add it to the local auth cache - final BasicScheme basicAuth = new BasicScheme(); - authCache.put(host, basicAuth); + // Generate DIGEST scheme object, initialize it and add it to the local auth cache + final DigestScheme digestAuth = new DigestScheme(); + // If we already know the realm name + digestAuth.overrideParamter("realm", "Custom Realm Name"); + + // digestAuth.overrideParamter("nonce", "MTM3NTU2OTU4MDAwNzoyYWI5YTQ5MTlhNzc5N2UxMGM5M2Y5M2ViOTc4ZmVhNg=="); + authCache.put(host, digestAuth); + // Add AuthCache to the execution context final BasicHttpContext localcontext = new BasicHttpContext(); localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache); diff --git a/spring-security-rest-digest-auth/src/main/java/org/baeldung/client/RestTemplateFactory.java b/spring-security-rest-digest-auth/src/main/java/org/baeldung/client/RestTemplateFactory.java deleted file mode 100644 index e8df87524c..0000000000 --- a/spring-security-rest-digest-auth/src/main/java/org/baeldung/client/RestTemplateFactory.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.baeldung.client; - -import org.apache.http.HttpHost; -import org.apache.http.client.HttpClient; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpParams; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; - -@Component -public class RestTemplateFactory implements FactoryBean, InitializingBean { - private RestTemplate restTemplate; - - public RestTemplateFactory() { - super(); - } - - // API - - @Override - public RestTemplate getObject() { - return restTemplate; - } - - @Override - public Class getObjectType() { - return RestTemplate.class; - } - - @Override - public boolean isSingleton() { - return true; - } - - @Override - public void afterPropertiesSet() { - final HttpHost host = new HttpHost("localhost", 8080, "http"); - final HttpComponentsClientHttpRequestFactoryBasicAuth requestFactory = new HttpComponentsClientHttpRequestFactoryBasicAuth(host); - restTemplate = new RestTemplate(requestFactory); - - final int timeout = 5; - final HttpClient httpClient = requestFactory.getHttpClient(); - // - note: timeout via raw String parameters - // httpClient.getParams().setParameter("http.connection.timeout", timeout * 1000); - // httpClient.getParams().setParameter("http.socket.timeout", timeout * 1000); - - // httpClient.getParams().setParameter("http.connection-manager.timeout", new Long(timeout * 1000)); - // httpClient.getParams().setParameter("http.protocol.head-body-timeout", timeout * 1000); - - // - note: timeout via the API - final HttpParams httpParams = httpClient.getParams(); - HttpConnectionParams.setConnectionTimeout(httpParams, timeout * 1000); // http.connection.timeout - HttpConnectionParams.setSoTimeout(httpParams, timeout * 1000); // http.socket.timeout - } - -} \ No newline at end of file diff --git a/spring-security-rest-digest-auth/src/main/java/org/baeldung/client/spring/ClientConfig.java b/spring-security-rest-digest-auth/src/main/java/org/baeldung/client/spring/ClientConfig.java index 73e602855c..615be8f524 100644 --- a/spring-security-rest-digest-auth/src/main/java/org/baeldung/client/spring/ClientConfig.java +++ b/spring-security-rest-digest-auth/src/main/java/org/baeldung/client/spring/ClientConfig.java @@ -1,10 +1,16 @@ package org.baeldung.client.spring; -import org.springframework.context.annotation.ComponentScan; +import org.apache.http.HttpHost; +import org.apache.http.client.HttpClient; +import org.apache.http.params.HttpConnectionParams; +import org.apache.http.params.HttpParams; +import org.baeldung.client.HttpComponentsClientHttpRequestFactoryDigestAuth; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; @Configuration -@ComponentScan("org.baeldung.client") public class ClientConfig { public ClientConfig() { @@ -13,4 +19,33 @@ public class ClientConfig { // beans + @Bean + public RestTemplate restTemplate() { + final HttpHost host = new HttpHost("localhost", 8080, "http"); + final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactoryDigestAuth(host); + final RestTemplate restTemplate = new RestTemplate(requestFactory); + + final int timeout = 5; + configureTimeouts(requestFactory, timeout); + + return restTemplate; + } + + // util + + private final void configureTimeouts(final HttpComponentsClientHttpRequestFactory requestFactory, final int timeout) { + final HttpClient httpClient = requestFactory.getHttpClient(); + // - note: timeout via raw String parameters + // httpClient.getParams().setParameter("http.connection.timeout", timeout * 1000); + // httpClient.getParams().setParameter("http.socket.timeout", timeout * 1000); + + // httpClient.getParams().setParameter("http.connection-manager.timeout", new Long(timeout * 1000)); + // httpClient.getParams().setParameter("http.protocol.head-body-timeout", timeout * 1000); + + // - note: timeout via the API + final HttpParams httpParams = httpClient.getParams(); + HttpConnectionParams.setConnectionTimeout(httpParams, timeout * 1000); // http.connection.timeout + HttpConnectionParams.setSoTimeout(httpParams, timeout * 1000); // http.socket.timeout + } + } \ No newline at end of file diff --git a/spring-security-rest-digest-auth/src/main/resources/webSecurityConfig.xml b/spring-security-rest-digest-auth/src/main/resources/webSecurityConfig.xml index ba3b0f9017..2dbcf84eee 100644 --- a/spring-security-rest-digest-auth/src/main/resources/webSecurityConfig.xml +++ b/spring-security-rest-digest-auth/src/main/resources/webSecurityConfig.xml @@ -11,7 +11,7 @@ - + diff --git a/spring-security-rest-digest-auth/src/test/java/org/baeldung/client/ClientLiveTest.java b/spring-security-rest-digest-auth/src/test/java/org/baeldung/client/ClientLiveTest.java index f63537ae6b..9ab6854f61 100644 --- a/spring-security-rest-digest-auth/src/test/java/org/baeldung/client/ClientLiveTest.java +++ b/spring-security-rest-digest-auth/src/test/java/org/baeldung/client/ClientLiveTest.java @@ -29,9 +29,10 @@ public class ClientLiveTest { public final void whenSecuredRestApiIsConsumed_then200OK() { final HttpComponentsClientHttpRequestFactory requestFactory = (HttpComponentsClientHttpRequestFactory) restTemplate.getRequestFactory(); final DefaultHttpClient httpClient = (DefaultHttpClient) requestFactory.getHttpClient(); - httpClient.getCredentialsProvider().setCredentials(new AuthScope("localhost", 8080, AuthScope.ANY_REALM), new UsernamePasswordCredentials("user", "userPass")); + httpClient.getCredentialsProvider().setCredentials(new AuthScope("localhost", 8080, AuthScope.ANY_REALM), new UsernamePasswordCredentials("user1", "user1Pass")); - final ResponseEntity responseEntity = restTemplate.exchange("http://localhost:8080/spring-security-rest-digest-auth/api/foos/1", HttpMethod.GET, null, Foo.class); + final String uri = "http://localhost:8080/spring-security-rest-digest-auth/api/foos/1"; + final ResponseEntity responseEntity = restTemplate.exchange(uri, HttpMethod.GET, null, Foo.class); System.out.println(responseEntity.getStatusCode()); } diff --git a/spring-security-rest-template/README.md b/spring-security-rest-template/README.md index 9030dffbd7..a857ddc778 100644 --- a/spring-security-rest-template/README.md +++ b/spring-security-rest-template/README.md @@ -6,3 +6,5 @@ ### Relevant Articles: - [RestTemplate with Basic Authentication in Spring](http://www.baeldung.com/2012/04/16/how-to-use-resttemplate-with-basic-authentication-in-spring-3-1) - [HttpClient Timeout](http://www.baeldung.com/httpclient-timeout) + +TODO: rename to: spring-security-rest-basic-auth \ No newline at end of file