jhipster-registry
jhipster-registry copied to clipboard
CORS problems since 5.0.0 on management and config endpoints
Overview of the issue
Since v5.0.0, the registry served behind a traefik proxy (or letsencrypt) on docker seems to have CORS issues on post methods ( authenticate, config/encrypt, management/loggers).
Sample configuration
jhipster-registry:
image: jhipster/jhipster-registry:v5.0.2
volumes:
- jhipster-registry-data:/root/.ssh
environment:
- _JAVA_OPTIONS=-Xmx512m -Xms256m
- SPRING_PROFILES_ACTIVE=prod
...
- LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_WEB_CORS=TRACE
- JHIPSTER_CORS_ALLOWED-ORIGINS=https://my.domain.name
- 'JHIPSTER_CORS_ALLOWED-METHODS=GET, PUT, POST, DELETE, OPTIONS'
- 'JHIPSTER_CORS_ALLOWED-HEADERS="*"'
- 'JHIPSTER_CORS_EXPOSED-HEADERS='
- 'JHIPSTER_CORS_ALLOW-CREDENTIALS=true'
networks:
- "traefik-public"
deploy:
replicas: 1
labels:
- traefik.frontend.rule=Host:my.domain.name
- traefik.enable=true
- traefik.port=8761
- traefik.tags=traefik-public
- traefik.docker.network=traefik-public
# Traefik service that listens to HTTP
- traefik.redirectorservice.frontend.entryPoints=http
- traefik.redirectorservice.frontend.redirect.entryPoint=https
# Traefik service that listens to HTTPS
- traefik.webservice.frontend.entryPoints=https
depends_on:
- traefik
The configuration worked in previous versions, but a http 403 'invalid cors request' is now returned.
I added
- JHIPSTER_CORS_ALLOWED-ORIGINS=https://my.domain.name
- 'JHIPSTER_CORS_ALLOWED-METHODS=GET, PUT, POST, DELETE, OPTIONS'
- 'JHIPSTER_CORS_ALLOWED-HEADERS="*"'
- 'JHIPSTER_CORS_EXPOSED-HEADERS='
- 'JHIPSTER_CORS_ALLOW-CREDENTIALS=true'
in the docker-compose, and it fixed the problem for /authenticate, but other POST on endpoints (like the encryption in configuration/encryption or changing the log levels) doesn't seems to share that configuration (they use the CORS configuration mapped to '/**' ).
Am I missing a property ?
Motivation for or Use Case
It worked in previous version ( before 5.0.0).
Reproduce the error
Start jhipster-registry on docker, served behind an https domain name.
JHipster Registry Version(s)
5.0.2
- [x] Checking this box is mandatory (this is just to show you read everything)
+1 here. Working before 5.0.0, now got invalid cors request at login
As per current implementation, configurable CORS settings are applied against following URI patterns in the WebConfigurer. If your URL path doesn't match against these patterns, then, the default CORS configuration is applied that deny the incoming request with 403.
source.registerCorsConfiguration("/eureka/**", config);
source.registerCorsConfiguration("/api/**", config);
source.registerCorsConfiguration("/v2/api-docs", config);
source.registerCorsConfiguration("/*/api/**", config);
To support customization, I think we can externalize these URL patterns like other CORS settings.
To fix the loggers, I added the following cors filters to WebConfigurer.corsFilter():
source.registerCorsConfiguration("/management/**", config);
source.registerCorsConfiguration("/auth/**", config);
source.registerCorsConfiguration("/services/*/api/**", config);
source.registerCorsConfiguration("/services/**/management/**", config);
source.registerCorsConfiguration("/*/management/**", config);
source.registerCorsConfiguration("/*/oauth/**", config);
To fix the swagger ui when combined with the jhipster uaa, I also replaced the OAuth2ClientCredentialsService.retrieveNewAccessToken() implementation with:
private void retrieveNewAccessToken() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
final String authString = jHipsterProperties.getSecurity().getClientAuthorization().getClientId() + ":" + jHipsterProperties.getSecurity().getClientAuthorization().getClientSecret();
final String authorization = "Basic " + Base64.encodeBase64String(authString.getBytes());
headers.add("Authorization", authorization);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("grant_type", "client_credentials");
HttpEntity<?> requestEntity = new HttpEntity<>(map, headers);
String tokenEndpoint = getTokenEndpoint();
ResponseEntity<DefaultOAuth2AccessToken> responseEntity = this.restTemplate.exchange(tokenEndpoint, HttpMethod.POST, requestEntity, DefaultOAuth2AccessToken.class);
if (!responseEntity.getStatusCode().is2xxSuccessful()) {
logger.debug("Request failed for '{}'", Optional.ofNullable(requestEntity.getHeaders()).map(HttpHeaders::getLocation).map(URI::toString).orElse(""));
}
accessToken = Objects.requireNonNull(responseEntity.getBody()).getValue();
}
/**
* Returns the configured OAuth2 token endpoint URI.
*
* @return the OAuth2 token endpoint URI.
*/
private String getTokenEndpoint() {
String tokenEndpointUrl = jHipsterProperties.getSecurity().getClientAuthorization().getAccessTokenUri();
if (tokenEndpointUrl == null) {
throw new InvalidClientException("no token endpoint configured in application properties");
}
return tokenEndpointUrl;
}