[英]Problems with HTTPS communications for RESTful client/server
我試圖在我編寫的使用Spring Boot提供RESTful功能的應用程序上通過HTTPS設置基於Web的安全性。 該應用程序僅使用HTTP即可按預期工作。
我已經對要在應用程序中“啟用” HTTPS所需做的工作進行了大量研究(至少我是這樣認為的),並將提供代碼段和配置的片段來說明我所擁有的。
我認為我已經接近了,但是還不能正常工作,我嘗試過的各種方法都沒有成功。
當前的實現不需要服務(服務器)驗證客戶端的憑據。 另外,我不需要任何形式的“用戶”身份驗證。
這是當前設置的簡要說明:
還有一個“虛擬”服務,可以簡單地將當前時間返回給客戶端的GET請求。 簡單的測試儀。
所有這五個元素都實現為@Service
,並且任務計划程序,“路由”服務和啞元具有對應的控制器( @RestController
),在這些控制器上映射了REST端點。
我具有為這三種服務(任務計划程序和兩個“路線”服務-假人僅使用“路線”證書之一)生成的證書,並且這些文件位於“密鑰庫”位置。 我還有一個“信任庫”位置,其中包含生成CA的公鑰。 所有這五個服務都具有信任庫。
我無法讓客戶與任何服務交談(為簡單起見,使用“虛擬”)。 我還嘗試通過Web瀏覽器訪問虛擬端點,結果似乎表明通信管道的某些部分正在發生但失敗。
以下是代碼片段,希望可以按代碼顯示圖片。
SERVER (以“虛擬”為例)
Dummy.java:
@Service
@Profile("dummy")
public class Dummy {
public String doIt() {
return Long.toString(System.currentTimeMillis());
}
}
DummyController.java:
@RestController
@RequestMapping("/rst")
@Profile("dummy")
public class DummyController {
@Autowired
private Dummy service;
@GetMapping(value = "/dummy", produces = "text/plain")
public String dummy() {
return service.doIt();
}
}
注意 :下面的類和application.yml中的屬性是我從網上找到的示例( https://github.com/indrabasak/spring-tls-example )改編而成的。 我不太理解已定義的“角色”的概念。 這里有很多我仍然不了解的地方。
SecurityConfiguration.java:
@Configuration
@EnableWebSecurity
@EnableConfigurationProperties(SecurityAuthProperties.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final Logger logger = LogManager.getLogger();
private final SecurityAuthProperties properties;
@Autowired
public SecurityConfiguration(SecurityAuthProperties properties) {
this.properties = properties;
}
@Override
public void configure(AuthenticationManagerBuilder auth) {
// properties.getUsers().forEach((key, value) -> {
// try {
// auth.inMemoryAuthentication()
// .passwordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder())
// .withUser(value.getId()).password(value.getPassword()).roles(value.getRoles());
// logger.info("Added user " + value.getId() + " with password " + value.getPassword());
// } catch (Exception e) {
// throw new SecurityConfigurationException(
// "Problem encountered while setting up authentication mananger", e);
// }
// });
}
@Override
public void configure(HttpSecurity http) throws Exception {
properties.getEndpoints().forEach((key, value) -> {
try {
for (HttpMethod method : value.getMethods()) {
// http.authorizeRequests().antMatchers(method, value.getPath())
// .hasAnyAuthority(value.getRoles()).and().httpBasic().and().csrf().disable();
http.authorizeRequests().antMatchers(method, value.getPath()).permitAll().and()
.httpBasic().and().csrf().disable();
logger.info("Added security for path " + value.getPath() + " and method " + method);
}
} catch (Exception e) {
throw new SecurityConfigurationException(
"Problem encountered while setting up endpoint restrictions", e);
}
});
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Override
public void configure(WebSecurity web) {
// TODO - what (if anything) do we do here?
}
}
SecurityAuthProperties.java :(“用戶”部分當前已取消,因為我們沒有使用它。)
@ConfigurationProperties("security.auth")
public class SecurityAuthProperties {
private static final String ROLE_PREFIX = "ROLE_";
public static final String ROLE_ANONYMOUS = "ROLE_ANONYMOUS";
private Map<String, Endpoint> endpoints = new HashMap<>();
// private Map<String, User> users = new HashMap<>();
@PostConstruct
public void init() {
endpoints.forEach((key, value) -> {
List<String> roles = new ArrayList<>();
for (String role : value.getRoles()) {
roles.add(ROLE_PREFIX + role);
}
value.setRoles(roles.toArray(new String[0]));
});
// users.forEach((key, value) -> {
// if (value.getId() == null) {
// value.setId(key);
// }
//
// if (value.getEncoding() != null) {
// value.setPassword("{" + value.getEncoding().trim() + "}" + value.getPassword());
// } else {
// value.setPassword("{noop}" + value.getPassword());
// }
// });
}
public Map<String, Endpoint> getEndpoints() {
return endpoints;
}
public void setEndpoints(Map<String, Endpoint> endpoints) {
this.endpoints = endpoints;
}
// public Map<String, User> getUsers() {
// return users;
// }
//
// public void setUsers(Map<String, User> users) {
// this.users = users;
// }
public static class Endpoint {
private String path;
private HttpMethod[] methods;
private String[] roles;
// trivial getters/setters removed for brevity
public String[] getRoles() {
if (roles == null || roles.length == 0) {
roles = new String[1];
roles[0] = ROLE_ANONYMOUS;
}
return roles;
}
}
public static class User {
private String id;
private String encoding;
private String password;
private String[] roles;
// trivial getters/setters removed for brevity
public String[] getRoles() {
if (roles == null || roles.length == 0) {
roles = new String[1];
roles[0] = ROLE_ANONYMOUS;
}
return roles;
}
}
}
application.yml:
...
server:
port: 8443
ssl:
enabled: true
protocol: TLS
trust-store-type: JKS
trust-store: classpath:truststore/server.truststore
trust-store-password: <password>
key-store-type: JKS
security:
auth:
endpoints:
endpoint1:
path: /rst/dummy
methods: GET
roles:
客戶
ClientService.java:
@Service
public class ClientService {
private final Logger logger = LogManager.getLogger();
private static final String REST_DUMMY = "rst/dummy";
// @Autowired
// private RestTemplate template;
@Value("${web.protocol:http}")
private String protocol;
@Value("${mission-planner.host:localhost}")
private String missionPlannerHost;
@Value("${mission-planner.port:8443}")
private int missionPlannerPort;
@Scheduled(fixedRate = 10000)
public void planMission() {
logger.info("ClientService.planMission()");
RestTemplate template = new RestTemplate();
String url = new URLBuilder.Builder().usingProtocol(protocol).onHost(missionPlannerHost)
.atPort(missionPlannerPort).atEndPoint(REST_DUMMY).build();
String response = template.getForObject(url, String.class);
}
}
我有一個大問題是,如果服務器不需要驗證客戶端,則需要在客戶端進行什么( 如果有的話 )“安全”配置? 我確實有很多嘗試在客戶端執行此操作的類/配置,但是當前已禁用。
使用所示的代碼,當我嘗試與虛擬服務進行通信時,我在客戶端上遇到異常:
org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://localhost:8443/rst/dummy": sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
更新
我決定嘗試將server.ssl.key-alias
(通過運行配置中的-D設置)更改為大寫(這似乎是證書所具有的),現在又得到了一個有趣的新異常。 注意:我還為客戶端和虛擬服務設置了javax.net.debug=ssl
。
scheduling-1, WRITE: TLSv1.2 Handshake, length = 196
scheduling-1, READ: TLSv1.2 Alert, length = 2
scheduling-1, RECV TLSv1.2 ALERT: fatal, handshake_failure
scheduling-1, called closeSocket()
scheduling-1, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
[2019-08-09 13:28:45.648] scheduling-1 ERROR: support.TaskUtils$LoggingErrorHandler:96 - Unexpected error occurred in scheduled task.
org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://localhost:8443/rst/dummy": Received fatal alert: handshake_failure; nested exception is javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
這就是我在服務中得到的:
matching alias: route_assessor_1
matching alias: route_assessor_1
qtp1060563153-39, fatal error: 40: no cipher suites in common
javax.net.ssl.SSLHandshakeException: no cipher suites in common
%% Invalidated: [Session-1, SSL_NULL_WITH_NULL_NULL]
qtp1060563153-39, SEND TLSv1.2 ALERT: fatal, description = handshake_failure
qtp1060563153-39, WRITE: TLSv1.2 Alert, length = 2
qtp1060563153-39, fatal: engine already closed. Rethrowing javax.net.ssl.SSLHandshakeException: no cipher suites in common
qtp1060563153-39, called closeOutbound()
qtp1060563153-39, closeOutboundInternal()
看來這是由於運動部件過多而忘記重新打開電源的情況。
經過大量的整理並返回原始源( https://github.com/indrabasak/spring-tls-example )並進行了一段時間的試驗之后,我看不出作者的工作之間有什么顯着差異代碼和我的無效代碼。
然后發生了其中一種突然的變化,我意識到我沒有在客戶端中使用安全配置的REST模板(由於我現在不記得的原因而被注釋掉了)。 我只是使用一個普通的未配置模板。
我取消注釋代碼,瞧瞧,客戶端現在驗證服務器的證書。
接下來的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.