NelmioCorsBundle
NelmioCorsBundle copied to clipboard
Duplicate control-header / control-origin
Hello,
I try to use this bundle for configure my api. But i have a problem since 2 weeks, and i didn't found any solution. Sorry for the inconvenience. My last configuration is :
Project on server : Debian 8 / nginx / php-fpm
Server side : Symfony 3.0 with FosUserBundle/ FOSRestBundle/ NelmioApiDocBundle / NelmioCorsBundle/ LexikJWTAuthenticationBundle / JMSSerializer
My config.yml :
# FosUserBundle Configuration
fos_user:
db_driver: orm
firewall_name: main
user_class: UserBundle\Entity\User
group:
group_class: UserBundle\Entity\Group
form:
type: UserBundle\Form\Type\GroupFormType
profile:
form:
type: UserBundle\Form\Type\ProfileFormType
# FOSRestBundle Configuration
fos_rest:
param_fetcher_listener: true
body_listener: true
format_listener: true
view:
view_response_listener: 'force'
formats:
xml: true
json : true
templating_formats:
html: true
force_redirects:
html: true
failed_validation: HTTP_BAD_REQUEST
default_engine: twig
routing_loader:
default_format: json
# LexikJWTAuthenticationBundle Configuration
lexik_jwt_authentication:
private_key_path: %jwt_private_key_path%
public_key_path: %jwt_public_key_path%
pass_phrase: %jwt_key_pass_phrase%
token_ttl: %jwt_token_ttl%
# JMSSerializer Configuration
jms_serializer:
metadata:
auto_detection: true
# NelmioCorsBundle Configuration
nelmio_cors:
defaults:
allow_credentials: true
allow_origin: []
allow_headers: []
allow_methods: []
expose_headers: []
max_age: 0
hosts: []
origin_regex: false
paths:
'^/api/':
allow_origin: ['*']
allow_headers: ['Origin', 'Content-Type', 'X-Requested-With', 'Accept']
allow_methods: ['POST', 'PUT', 'GET', 'DELETE', 'OPTIONS']
max_age: 3600
My security.yml :
api_doc:
pattern: ^/api/doc
anonymous: true
api_login:
pattern: ^/api/login
provider: fos_userbundle
stateless: true
anonymous: true
form_login:
check_path: /api/login_check
require_previous_session: false
username_parameter: username
password_parameter: password
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
api:
pattern: ^/api
stateless: true
provider: fos_userbundle
lexik_jwt:
authorization_header:
enabled: true
prefix: Bearer
query_parameter:
enabled: true
name: Bearer
throw_exceptions: true
create_entry_point: true
## Main firewall
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
login_path: fos_user_security_login
check_path: fos_user_security_check
remember_me: true
default_target_path: lgb_onepage_home
logout:
path: fos_user_security_logout
target: lgb_onepage_home
anonymous: true
remember_me:
secret: %secret%
lifetime: 604800 # 1 week in seconds
path: /
domain: ~ # Defaults to the current domain from $_SERVER
# secure: true
httponly: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: ROLE_ADMIN }
- { path: ^/resetting, role: ROLE_ADMIN }
- { path: ^/intranet/, role: ROLE_USER }
- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/doc, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: [IS_AUTHENTICATED_FULLY, ROLE_ADMIN] }
And for my client, i use Ionic with angular JS on base project (with skeleton tabs for have a valid login form) :
My config :
.config(function ($stateProvider, $urlRouterProvider, localStorageServiceProvider, $httpProvider) {
$stateProvider...;
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/app/playlists');
localStorageServiceProvider
.setPrefix('lgb-preorder');
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
});
and my function (doesn't work):
$scope.doLogin = function () {
var loginData = {
username: this.login.username,
password: this.login.password
};
$http({
url: 'http://sub.domain.com/app_dev.php/api/login_check',
method: 'POST',
data: loginData,
headers: {'Content-Type': 'application/json'}
})
.success(function (data) {
console.log("Success -- login ok with ", data);
})
.error(function (error) {
console.log("ERROR -- login fail with ", error);
});
};
Error send is :
XMLHttpRequest cannot load http://sub.domain.com/app_dev.php/api/login_check. Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header contains multiple values '*, http://localhost:8100', but only one is allowed. Origin 'http://localhost:8100' is therefore not allowed access.
it seems because my http request have 2 definitions of Access-Control-Allow-Headers and Access-Control-Allow-Origin :
Request URL:http://sub.domain.com/app_dev.php/api/login_check
Request Method:OPTIONS
Status Code:200 OK
Remote Address:x.x.x.x:80
Response Headers
view source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Headers:origin, content-type, x-requested-with, accept
Access-Control-Allow-Methods:POST, PUT, GET, DELETE, OPTIONS
Access-Control-Allow-Origin:http://localhost:8100
Access-Control-Allow-Origin:*
Access-Control-Max-Age:3600
but why ???____??? It seems i have 2 different handler, nelmio and one other, and each put an Access-Control-Allow-Headers / Access-Control-Allow-Origin. The others access-control are OK.
If anyone have an idea, its really appreciated. Thanx for your help.
Anyone have an idea ?? :s
up, if someone have an idea ??
up, i continue to search a solution .. If anyone have an idea
last up, i didn't find any solution currently. I search about nginx configuration, may be its a conflict between nginx vhost and this bundle
I can confirm that if Nginx is also configured to send the CORS headers, there are duplicates created. I removed the Nginx CORS config and the bundle works as expected. An idea is to have the bundle check for the headers and create a warning if duplicates are present.
I can confirm that if Nginx is also configured to send the CORS headers, there are duplicates created. I removed the Nginx CORS config and the bundle works as expected. An idea is to have the bundle check for the headers and create a warning if duplicates are present.
Can confirm, had exactly same problem.
+1 symfony: 5.4 nelmiocors: 2.2.0
+1 Symfony: 5.3.15 Nelmiocors: 2.2.0
The bundle is asf ar as I know never setting duplicate headers, so if you're +1ing here, please give more details or look at what else you have running in your application. Try to look in the symfony profiler for what event listeners you have running after the CorsListener. Do you have symfony http cache in place or something? Just adding +1 will not help anyone that's for sure.
An idea is to have the bundle check for the headers and create a warning if duplicates are present.
The bundle cannot do this check, if you configure your web server to also send CORS headers back in the response what happens is this:
- web server gets a request
- forwards to php
- PHP runs, Symfony runs, NelmioCorsBundle adds headers
- web server gets back a response
- web server adds duplicate headers
- web server sends the response back to client
As you can see, the PHP code has no chance to ever see what the web server is doing, so cannot act on that. Only the server admins/application developers can do this. Please learn how your stack works.