Commit da6cce71 by Johannes Stelzer

Support http-basic authorization in registration.

This allows you to protect your spring-boot-admin rest api. Supporting basic auth on management-endpoints needs more work.
parent 7eb4bafc
...@@ -102,6 +102,7 @@ public class LogfileMvcEndpoint implements MvcEndpoint { ...@@ -102,6 +102,7 @@ public class LogfileMvcEndpoint implements MvcEndpoint {
Resource file = new FileSystemResource(logfile); Resource file = new FileSystemResource(logfile);
response.setContentType(MediaType.TEXT_PLAIN_VALUE); response.setContentType(MediaType.TEXT_PLAIN_VALUE);
response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getFilename() + "\"");
FileCopyUtils.copy(file.getInputStream(), response.getOutputStream()); FileCopyUtils.copy(file.getInputStream(), response.getOutputStream());
} }
......
...@@ -18,7 +18,7 @@ package de.codecentric.boot.admin.config; ...@@ -18,7 +18,7 @@ package de.codecentric.boot.admin.config;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "spring.boot.admin.client") @ConfigurationProperties(prefix = "spring.boot.admin.client", ignoreUnknownFields = false)
public class AdminClientProperties { public class AdminClientProperties {
@Value("http://#{T(java.net.InetAddress).localHost.canonicalHostName}:${server.port:${management.port:8080}}${management.context-path:/}") @Value("http://#{T(java.net.InetAddress).localHost.canonicalHostName}:${server.port:${management.port:8080}}${management.context-path:/}")
......
...@@ -26,6 +26,10 @@ public class AdminProperties { ...@@ -26,6 +26,10 @@ public class AdminProperties {
private int period = 10000; private int period = 10000;
private String username;
private String password;
public void setUrl(String url) { public void setUrl(String url) {
this.url = url; this.url = url;
} }
...@@ -38,7 +42,6 @@ public class AdminProperties { ...@@ -38,7 +42,6 @@ public class AdminProperties {
return url; return url;
} }
/** /**
* @return the Spring Boot Admin Server's context path. * @return the Spring Boot Admin Server's context path.
*/ */
...@@ -61,4 +64,27 @@ public class AdminProperties { ...@@ -61,4 +64,27 @@ public class AdminProperties {
public void setPeriod(int period) { public void setPeriod(int period) {
this.period = period; this.period = period;
} }
public void setUsername(String username) {
this.username = username;
}
/**
* @return username for basic authentication .
*/
public String getUsername() {
return username;
}
public void setPassword(String password) {
this.password = password;
}
/**
*
* @return password for basic authentication.
*/
public String getPassword() {
return password;
}
} }
...@@ -15,17 +15,22 @@ ...@@ -15,17 +15,22 @@
*/ */
package de.codecentric.boot.admin.config; package de.codecentric.boot.admin.config;
import java.util.Arrays;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.scheduling.config.ScheduledTaskRegistrar; import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import de.codecentric.boot.admin.actuate.LogfileMvcEndpoint; import de.codecentric.boot.admin.actuate.LogfileMvcEndpoint;
import de.codecentric.boot.admin.services.SpringBootAdminRegistrator; import de.codecentric.boot.admin.services.SpringBootAdminRegistrator;
import de.codecentric.boot.admin.web.BasicAuthHttpRequestInterceptor;
import de.codecentric.boot.admin.web.SimpleCORSFilter; import de.codecentric.boot.admin.web.SimpleCORSFilter;
/** /**
...@@ -41,16 +46,20 @@ public class SpringBootAdminClientAutoConfiguration { ...@@ -41,16 +46,20 @@ public class SpringBootAdminClientAutoConfiguration {
* Task that registers the application at the spring-boot-admin application. * Task that registers the application at the spring-boot-admin application.
*/ */
@Bean @Bean
public SpringBootAdminRegistrator registrator(AdminProperties adminProps, @ConditionalOnMissingBean
AdminClientProperties clientProps) { public SpringBootAdminRegistrator registrator(AdminProperties adminProps, AdminClientProperties clientProps) {
return new SpringBootAdminRegistrator(restTemplate(), adminProps, clientProps); return new SpringBootAdminRegistrator(createRestTemplate(adminProps), adminProps, clientProps);
} }
protected RestTemplate createRestTemplate(AdminProperties adminProps) {
@Bean
public RestTemplate restTemplate() {
RestTemplate template = new RestTemplate(); RestTemplate template = new RestTemplate();
template.getMessageConverters().add(new MappingJackson2HttpMessageConverter()); template.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
if (adminProps.getUsername() != null) {
template.setInterceptors(Arrays.<ClientHttpRequestInterceptor> asList(new BasicAuthHttpRequestInterceptor(
adminProps.getUsername(), adminProps.getPassword())));
}
return template; return template;
} }
......
package de.codecentric.boot.admin.web;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import com.fasterxml.jackson.core.Base64Variants;
public class BasicAuthHttpRequestInterceptor implements ClientHttpRequestInterceptor {
private final String encodedAuth;
public BasicAuthHttpRequestInterceptor(String username, String password) {
String auth = username + ":" + password;
encodedAuth = "Basic " + Base64Variants.MIME_NO_LINEFEEDS.encode(auth.getBytes(StandardCharsets.US_ASCII));
}
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
throws IOException {
request.getHeaders().add("Authorization", encodedAuth);
return execution.execute(request, body);
}
}
package de.codecentric.boot.admin.web;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.util.Collections;
import org.junit.Test;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.mock.http.client.MockClientHttpRequest;
import de.codecentric.boot.admin.web.BasicAuthHttpRequestInterceptor;
public class BasicAuthHttpRequestInterceptorTest {
@Test
public void test() throws IOException {
BasicAuthHttpRequestInterceptor interceptor = new BasicAuthHttpRequestInterceptor("admin", "secret");
HttpRequest request = new MockClientHttpRequest();
interceptor.intercept(request, (byte[]) null, new ClientHttpRequestExecution() {
@Override
public ClientHttpResponse execute(HttpRequest paramHttpRequest, byte[] paramArrayOfByte) throws IOException {
return null;
}
});
assertEquals(Collections.singletonList("Basic YWRtaW46c2VjcmV0"), request.getHeaders().get("Authorization"));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment