1

我正在使用Gluu Server并尝试/.well-known/openid-configuration通过 CORS/AJAX 请求(用于 Angular 应用程序)从端点获取 OpenID Connect 配置。但是,当我尝试使用 XHR 请求端点从本地托管的应用程序/HTML 文件请求端点时,我收到一个403 Forbidden错误。

这似乎只发生在请求来自本地上下文时,即 Angular 的开发服务器或请求端点的本地 HTML 文件。如果我打开托管在服务器上的执行 AJAX 请求的同一个 HTML 文件,它就可以工作。

测试 HTML 文件如下所示

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <div id="content"></div>
    <script type="text/javascript">
        var url = 'https://example.com/.well-known/openid-configuration';

        var req = new XMLHttpRequest();

        req.open('GET', url, true);
        req.setRequestHeader('Content-Type', 'application/json');

        req.onload = () => {
            if (req.status >= 200 && req.status < 400) {
                console.log('[XHR SUCCESS]');
                var el = document.getElementById('content');
                el.innerHTML = req.responseText;
            } else {
                console.log('[XHR ERROR]', req);
            }
        }

        req.onerror = () => {
            console.log('[XHR CONNECTION ERROR]');
        }
        req.send();
    </script>
</body>
</html>

从本地文件请求

如上所述,当从本地 HTML 文件请求时,我收到403 Forbidden错误消息。

在浏览器控制台(Chrome)中,输出两个错误:

Failed to load resource: the server responded with a status of 403 (Forbidden)
Access to XMLHttpRequest at 'https://example.com/.well-known/openid-configuration' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

我发现与此相关的服务器上唯一的输出在文件中/var/log/apache2/other_vhosts_access.log

example.com:443 <IP> - - [11/Mar/2019:10:45:20 +0000] "OPTIONS /.well-known/openid-configuration HTTP/1.1" 403 3763 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"

当从本地请求时,服务器会收到以下信息(来自log_forensicApache 模块):

OPTIONS /.well-known/openid-configuration HTTP/1.1|Host:example.com|Connection:keep-alive|Pragma:no-cache|Cache-Control:no-cache|Access-Control-Request-Method:GET|Origin:null|User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36|Access-Control-Request-Headers:content-type|Accept:*/*|Accept-Encoding:gzip, deflate, br|Accept-Language:en-US,en;q=0.9

从服务器托管文件请求

执行与上述完全相同的操作,但 HTML 文件托管在服务器上时,请求成功完成。

访问日志中的输出:

example.com:443 <IP> - - [11/Mar/2019:11:06:46 +0000] "OPTIONS /.well-known/openid-configuration HTTP/1.1" 200 779 "http://example.org/xhr-cors.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"
example.com:443 <IP> - - [11/Mar/2019:11:06:46 +0000] "GET /.well-known/openid-configuration HTTP/1.1" 200 6629 "http://example.org/xhr-cors.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"

来自log_forensic

OPTIONS /.well-known/openid-configuration HTTP/1.1|Host:example.com|Connection:keep-alive|Access-Control-Request-Method:GET|Origin:http%3a//example.org|User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36|Access-Control-Request-Headers:content-type|Accept:*/*|Referer:http%3a//example.org/xhr-cors.html|Accept-Encoding:gzip, deflate, br|Accept-Language:en-US,en;q=0.9

GET /.well-known/openid-configuration HTTP/1.1|Host:example.com|Connection:keep-alive|Origin:http%3a//example.org|User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36|Content-Type:application/json|Accept:*/*|Referer:http%3a//example.org/xhr-cors.html|Accept-Encoding:gzip, deflate, br|Accept-Language:en-US,en;q=0.9

阿帕奇配置

服务器上 Apache 的配置是

<VirtualHost  *:80>
        ServerName example.com
        Redirect  / https://example.com/
        DocumentRoot "/var/www/html/"
RewriteEngine on
RewriteCond %{SERVER_NAME} =example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

<VirtualHost *:443>
        DocumentRoot "/var/www/html/"
        ServerName example.com:443

        LogLevel warn
        SSLEngine on
        SSLProtocol -all +TLSv1.1 +TLSv1.2
        SSLHonorCipherOrder On
        SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:DHE-RSA-AES128-SHA256:DHE-DSS-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:DHE-RSA-AES128-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK

#               SetEnv proxy-nokeepalive 1
        SetEnv proxy-initial-not-pooled 1
        Timeout 60
                ProxyTimeout 60

        # Security headers
#        Header always append X-Frame-Options SAMEORIGIN
                Header always set X-Xss-Protection "1; mode=block"
                Header always set X-Content-Type-Options nosniff
#        Header always set Content-Security-Policy "default-src 'self' 'unsafe-inline' https://example.com"
        Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

        Header edit Set-Cookie ^((?!session_state).*)$ $1;HttpOnly
        SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0

                # Unset X-ClientCert to make sure that we not get certificate in request
        RequestHeader unset X-ClientCert

                # Turn off support for true Proxy behaviour as we are acting as a transparent proxy
        ProxyRequests Off

                # Turn off VIA header as we know where the requests are proxied
        ProxyVia Off

                # Turn on Host header preservation so that the servlet container
                # can write links with the correct host and rewriting can be avoided.
        ProxyPreserveHost On

                # Preserve the scheme when proxying the request to Jetty
                RequestHeader set X-Forwarded-Proto "https" env=HTTPS

                Header unset ETag
        FileETag None

        RedirectMatch ^(/)$ /identity/

                # Set the permissions for the proxy
                <Proxy *>
                  AddDefaultCharset off
                  Order deny,allow
                  Allow from all
                </Proxy>

        <Location /oxauth>
                ProxyPass http://localhost:8081/oxauth retry=5 connectiontimeout=60 timeout=60
#                Header set Access-Control-Allow-Origin "*"
                Order deny,allow
                Allow from all
        </Location>

        <LocationMatch /oxauth/auth/cert/cert-login>
            SSLVerifyClient optional_no_ca
            SSLVerifyDepth 10
            SSLOptions -StdEnvVars +ExportCertData

                        # Forward certificate to destination server
            RequestHeader set X-ClientCert %{SSL_CLIENT_CERT}s
        </LocationMatch>

        <Location /idp>
                ProxyPass http://localhost:8086/idp retry=5 connectiontimeout=60 timeout=60
                Order deny,allow
                Allow from all
        </Location>

        <Location /identity>
                ProxyPass http://localhost:8082/identity retry=5 connectiontimeout=60 timeout=60
                Order deny,allow
                Allow from all
        </Location>

        <Location /cas>
                ProxyPass http://localhost:8083/cas retry=5 connectiontimeout=60 timeout=60
                Order deny,allow
                Allow from all
        </Location>

        <Location /oxauth-rp>
                ProxyPass http://localhost:8085/oxauth-rp retry=5 connectiontimeout=60 timeout=60
                Order deny,allow
                Allow from all
        </Location>

        <Location /asimba>
                ProxyPass http://localhost:8084/asimba retry=5 connectiontimeout=60 timeout=60
                Order deny,allow
                Allow from all
        </Location>

        <Location /passport>
                ProxyPass http://localhost:8090/passport retry=5 connectiontimeout=60 timeout=60
                Order deny,allow
                Allow from all
        </Location>

        <Location /casa>
                ProxyPass http://localhost:8091/casa retry=5 connectiontimeout=60 timeout=60
                Order deny,allow
                Allow from all
        </Location>

       <LocationMatch "/.well-known/openid-configuration">
               ProxyPass http://localhost:8081/oxauth/.well-known/openid-configuration
               Header set Access-Control-Allow-Origin "*"
       </LocationMatch>

#                        ProxyPass /.well-known/openid-configuration http://localhost:8081/oxauth/.well-known/openid-configuration
ProxyPass /.well-known/simple-web-discovery http://localhost:8081/oxauth/.well-known/simple-web-discovery
ProxyPass        /.well-known/webfinger http://localhost:8081/oxauth/.well-known/webfinger
        ProxyPass        /.well-known/uma2-configuration http://localhost:8081/oxauth/restv1/uma2-configuration
        ProxyPass        /.well-known/fido-configuration http://localhost:8081/oxauth/restv1/fido-configuration
        ProxyPass        /.well-known/fido-u2f-configuration http://localhost:8081/oxauth/restv1/fido-configuration
        ProxyPass        /.well-known/scim-configuration http://localhost:8082/identity/restv1/scim-configuration
        ServerAlias        example.com
        SSLCertificateFile        /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>

我已经注释掉了

ProxyPass /.well-known/openid-configuration http://localhost:8081/oxauth/.well-known/openid-configuration

指令并介绍了

<LocationMatch "/.well-known/openid-configuration">
        ProxyPass http://localhost:8081/oxauth/.well-known/openid-configuration
        Header set Access-Control-Allow-Origin "*"
</LocationMatch>

添加 CORS 标头的指令。

其他

我试图找出问题所在的其他事情:

  • 通过 Postman 向端点执行GET请求,成功完成。
  • 通过 Postman 向端点执行OPTIONS请求,成功完成。

我非常感谢对此的一些意见,因为它让我很困惑,并且在开发时无法在本地工作很麻烦。如果需要任何澄清,请告诉我。

4

1 回答 1

1

原来这个问题是两个不相关的事情的合并。

首先,这主要是推测, Chrome似乎阻止了来自本地文件(HTML 文件)的请求,只是提供了对我来说非常混乱的输出。即403错误可能是因为 Chrome 以某种方式阻止了 CORS 请求。我尝试使用各种标志运行 Chrome,例如--disable-web-security--allow-file-access-from-files,但这并没有改变本地 HTML 文件的输出。所以,本地文件请求仍然失败,我真的不知道确切的原因。但是,由于这只是为了测试,所以目前对我来说并没有那么重要。

其次,Angular 项目的拦截器中的错误实现覆盖了请求的所有标头。修复此问题后,本地服务器能够请求端点。

碰巧这两个不同问题的输出看起来几乎相同,这让我很反感。

于 2019-03-13T14:30:19.103 回答