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;
}