英文:
Why is flask redirect turning an external URL into a local URL while using reverse proxy in IIS?
问题
以下是您要翻译的内容:
"Just for some background, I have been trying to set up Azure AD OAuth authentication using flask dance. The actual issue I'm having is when redirecting to the authorization URL, flask is not redirecting as I would expect it to.
I've tried using a simple redirect like this:
@oauth_blueprint.route('/')
def route_oauth():
return flask.redirect('https://login.microsoftonline.com/tenant/oauth2/v2.0/authorize')
Now, if I access the page directly at localhost:5000/oauth then it works as expected and redirects me to the URL.
However, our web application is set up using a reverse proxy. The flask application is accessed at www.example.com/flask/xxx which returns the corresponding page at localhost:5000/xxx. So if I go to www.example.com/flask/oauth then I should get the same page as localhost:5000/oauth.
So the problem is when I go to www.example.com/flask/oauth the redirect does not work correctly. Instead of taking me to https://login.microsoftonline.com/tenant/oauth2/v2.0/authorize, I instead get redirected to www.example.com/tenant/oauth2/v2.0/authorize. I can't make sense of this as the URL is clearly not a relative URL.
In case it's relevant, we are using URL Rewrite in IIS. There is a simple rewrite rule which matches any URL starting with flask/. This has worked fine for all our other pages.
This is what the rule looks like in IIS:
I've tried using FRT to trace the rewrite. Below is the output I got. It changes to the undesired URL at line 27 but I don't understand why.
No. | EventName | Details | Time |
---|---|---|---|
1. | GENERAL_REQUEST_START | SiteId="2", AppPoolId="App", ConnId="1610613017", RawConnId="1610613017", RequestURL="http://www.example.com/flask/oauth/", RequestVerb="GET" | 12:35:02.963 |
2. | GENERAL_ENDPOINT_INFORMATION | RemoteAddress="::1", RemotePort="64068", LocalAddress="::1", LocalPort="81" | 12:35:02.963 |
3. | GENERAL_REQUEST_HEADERS | Headers="Connection: keep-alive Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 Host: www.example.com User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.82 sec-ch-ua: "Not.A/Brand";v="8", "Chromium";v="114", "Microsoft Edge";v="114" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows" Upgrade-Insecure-Requests: 1 Sec-Fetch-Site: none Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document " | 12:35:02.963 |
4. | GENERAL_GET_URL_METADATA | PhysicalPath="", AccessPerms="513" | 12:35:02.963 |
5. | HANDLER_CHANGED | OldHandlerName="", NewHandlerName="StaticFile", NewHandlerModules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule", NewHandlerScriptProcessor="", NewHandlerType="" | 12:35:02.963 |
6. | URL_REWRITE_START | RequestURL="/flask/oauth/", Scope="Distributed", Type="Inbound" | 12:35:02.963 |
7. | RULE_EVALUATION_START | RuleName="Flask", RequestURL="flask/oauth/", QueryString="", PatternSyntax="Regex", StopProcessing="true", RelativePath="/" | 12:35:02.963 |
8. | PATTERN_MATCH | Pattern="^flask/(.*)", Input="flask/oauth/", Negate="false", Matched="true" | 12:35:02.963 |
9. | REWRITE_ACTION | Substitution="http://localhost:5000/{R:1}", RewriteURL="http://localhost:5000/oauth/", AppendQueryString="true", LogRewrittenURL="true" | 12:35:02.963 |
10. | RULE_EVALUATION_END | RuleName="Flask", RequestURL="http://localhost:5000/oauth/", QueryString="", StopProcessing="true", Succeeded="true" | 12:35:02.963 |
11. | GENERAL_SET_REQUEST_HEADER | HeaderName="X-Original-URL", HeaderValue="/flask/oauth/", Replace="true" | 12:35:02.963 |
12. | URL_CHANGED | OldUrl="http://localhost:5000/oauth/", NewUrl="/flask/oauth/" | 12:35:02.963 |
13. | URL_REWRITE_END | RequestURL="http://localhost:5000/oauth/" | 12:35:02.963 |
14. | USER_SET | AuthType="", UserName="", SupportsIsInRole="true" | 12:35:02.963 |
15. | HANDLER_CHANGED | OldHandlerName="StaticFile", NewHandlerName="ApplicationRequestRoutingHandler", NewHandlerModules="ApplicationRequestRouting", NewHandlerScriptProcessor="", NewHandlerType="" | 12:35:02.963 |
16. | GENERAL_SET_REQUEST_HEADER | HeaderName="Max-Forwards", HeaderValue="10", Replace="true" | 12:35:02.963 |
17. | GENERAL_SET_REQUEST_HEADER | HeaderName="X-Forwarded-For", HeaderValue="[::1]", Replace="true" | 12:35:02.963 |
18. | GENERAL_SET_REQUEST_HEADER | HeaderName="X-ARR-SSL", HeaderValue="", Replace="true" | 12:35:02.963 |
19. | GENERAL_SET_REQUEST_HEADER | HeaderName="X-ARR-ClientCert", HeaderValue="", Replace="true" | 12:35:02.963 |
20. | GENERAL_SET_REQUEST |
英文:
Just for some background, I have been trying to set up Azure AD OAuth authentication using flask dance. The actual issue I'm having is when redirecting to the authorization URL, flask is not redirecting as I would expect it to.
I've tried using a simple redirect like this:
@oauth_blueprint.route('/')
def route_oauth():
return flask.redirect('https://login.microsoftonline.com/tenant/oauth2/v2.0/authorize')
Now, if I access the page directly at localhost:5000/oauth
then it works as expected and redirects me to the URL.
However, our web application is set up using a reverse proxy. The flask application is accessed at www.example.com/flask/xxx
which returns the corresponding page at localhost:5000/xxx
. So if I go to www.example.com/flask/oauth
then I should get the same page as localhost:5000/oauth
.
So the problem is when I go to www.example.com/flask/oauth
the redirect does not work correctly. Instead of taking me to https://login.microsoftonline.com/tenant/oauth2/v2.0/authorize
, I instead get redirected to www.example.com/tenant/oauth2/v2.0/authorize
. I can't make sense of this as the URL is clearly not a relative URL.
In case it's relevant, we are using URL Rewrite in IIS. There is a simple rewrite rule which matches any URL starting with flask/
. This has worked fine for all our other pages.
This is what the rule looks like in IIS:
I've tried using FRT to trace the rewrite. Below is the output I got. It changes to the undesired URL at line 27 but I don't understand why.
| No. | EventName | Details | Time |
| --- | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
| 1. | GENERAL_REQUEST_START | SiteId="2", AppPoolId="App", ConnId="1610613017", RawConnId="1610613017", RequestURL="http://www.example.com/flask/oauth/", RequestVerb="GET" | 12:35:02.963 |
| 2. | GENERAL_ENDPOINT_INFORMATION | RemoteAddress="::1", RemotePort="64068", LocalAddress="::1", LocalPort="81" | 12:35:02.963 |
| 3. | GENERAL_REQUEST_HEADERS | Headers="Connection: keep-alive Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,\*/\*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 Host: www.example.com User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.82 sec-ch-ua: "Not.A/Brand";v="8", "Chromium";v="114", "Microsoft Edge";v="114" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows" Upgrade-Insecure-Requests: 1 Sec-Fetch-Site: none Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document " | 12:35:02.963 |
| 4. | GENERAL_GET_URL_METADATA | PhysicalPath="", AccessPerms="513" | 12:35:02.963 |
| 5. | HANDLER_CHANGED | OldHandlerName="", NewHandlerName="StaticFile", NewHandlerModules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule", NewHandlerScriptProcessor="", NewHandlerType="" | 12:35:02.963 |
| 6. | URL_REWRITE_START | RequestURL="/flask/oauth/", Scope="Distributed", Type="Inbound" | 12:35:02.963 |
| 7. | RULE_EVALUATION_START | RuleName="Flask", RequestURL="flask/oauth/", QueryString="", PatternSyntax="Regex", StopProcessing="true", RelativePath="/" | 12:35:02.963 |
| 8. | PATTERN_MATCH | Pattern="^flask/(.\*)", Input="flask/oauth/", Negate="false", Matched="true" | 12:35:02.963 |
| 9. | REWRITE_ACTION | Substitution="http://localhost:5000/{R:1}", RewriteURL="http://localhost:5000/oauth/", AppendQueryString="true", LogRewrittenURL="true" | 12:35:02.963 |
| 10. | RULE_EVALUATION_END | RuleName="Flask", RequestURL="http://localhost:5000/oauth/", QueryString="", StopProcessing="true", Succeeded="true" | 12:35:02.963 |
| 11. | GENERAL_SET_REQUEST_HEADER | HeaderName="X-Original-URL", HeaderValue="/flask/oauth/", Replace="true" | 12:35:02.963 |
| 12. | URL_CHANGED | OldUrl="/flask/oauth/", NewUrl="http://localhost:5000/oauth/" | 12:35:02.963 |
| 13. | URL_REWRITE_END | RequestURL="http://localhost:5000/oauth/" | 12:35:02.963 |
| 14. | USER_SET | AuthType="", UserName="", SupportsIsInRole="true" | 12:35:02.963 |
| 15. | HANDLER_CHANGED | OldHandlerName="StaticFile", NewHandlerName="ApplicationRequestRoutingHandler", NewHandlerModules="ApplicationRequestRouting", NewHandlerScriptProcessor="", NewHandlerType="" | 12:35:02.963 |
| 16. | GENERAL_SET_REQUEST_HEADER | HeaderName="Max-Forwards", HeaderValue="10", Replace="true" | 12:35:02.963 |
| 17. | GENERAL_SET_REQUEST_HEADER | HeaderName="X-Forwarded-For", HeaderValue="[::1]", Replace="true" | 12:35:02.963 |
| 18. | GENERAL_SET_REQUEST_HEADER | HeaderName="X-ARR-SSL", HeaderValue="", Replace="true" | 12:35:02.963 |
| 19. | GENERAL_SET_REQUEST_HEADER | HeaderName="X-ARR-ClientCert", HeaderValue="", Replace="true" | 12:35:02.963 |
| 20. | GENERAL_SET_REQUEST_HEADER | HeaderName="X-ARR-LOG-ID", HeaderValue="0f2e2610-c6a8-4412-be80-431075354701", Replace="true" | 12:35:02.963 |
| 21. | GENERAL_SET_REQUEST_HEADER | HeaderName="Connection", HeaderValue="", Replace="true" | 12:35:02.963 |
| 22. | URL_CHANGED | OldUrl="http://localhost:5000/oauth/", NewUrl="/flask/oauth/" | 12:35:02.963 |
| 23. | GENERAL_SET_RESPONSE_HEADER | HeaderName="Content-Length", HeaderValue="371", Replace="true" | 12:35:02.963 |
| 24. | GENERAL_SET_RESPONSE_HEADER | HeaderName="Content-Type", HeaderValue="text/html; charset=utf-8", Replace="true" | 12:35:02.963 |
| 25. | GENERAL_SET_RESPONSE_HEADER | HeaderName="Location", HeaderValue="https://login.microsoftonline.com/tenant/oauth2/v2.0/authorize", Replace="true" | 12:35:02.963 |
| 26. | GENERAL_SET_RESPONSE_HEADER | HeaderName="Access-Control-Allow-Origin", HeaderValue="/..", Replace="false" | 12:35:02.963 |
| 27. | GENERAL_SET_RESPONSE_HEADER | HeaderName="Location", HeaderValue="http://www.example.com/tenant/oauth2/v2.0/authorize", Replace="true" | 12:35:02.963 |
| 28. | GENERAL_SET_RESPONSE_HEADER | HeaderName="X-Powered-By", HeaderValue="ARR/3.0", Replace="false" | 12:35:02.963 |
| 29. | GENERAL_NOT_SEND_CUSTOM_ERROR | Reason="SETSTATUS_SUCCESS" | 12:35:02.963 |
| 30. | GENERAL_FLUSH_RESPONSE_START | | 12:35:02.963 |
| 31. | GENERAL_RESPONSE_HEADERS | Headers="Content-Type: text/html; charset=utf-8 Location: http://www.example.com/tenant/oauth2/v2.0/authorize Server: Microsoft-IIS/10.0 Access-Control-Allow-Origin: /.. X-Powered-By: ARR/3.0 " | 12:35:02.963 |
| 32. | GENERAL_RESPONSE_ENTITY_BUFFER | Buffer="<!doctype html> <html lang=en> <title>Redirecting...</title> <h1>Redirecting...</h1> <p>You should be redirected automatically to the target URL: <a href="https://login.microsoftonline.com/tenant/oauth2/v2.0/authorize">https://login.microsoftonline.com/tenant/oauth2/v2.0/authorize</a>. If not, click the link. " | 12:35:02.963 |
| 33. | GENERAL_FLUSH_RESPONSE_END | BytesSent="666", ErrorCode="The operation completed successfully. (0x0)" | 12:35:02.963 |
| 34. | GENERAL_REQUEST_END | BytesSent="666", BytesReceived="1028", HttpStatus="302", HttpSubStatus="0" | 12:35:02.963 |
I'd really appreciate any help on this issue. I'm happy to provide any more details if necessary. Thank you.
答案1
得分: 1
我仔细阅读了您提供的FRT日志。
在第13行,在URL重写之后,请求URL现在是"http://localhost:5000/oauth/",这意味着重写成功。
在第25行:将"Location"响应头设置为"https://login.microsoftonline.com/tenant/oauth2/v2.0/authorize"。这可能是应用程序逻辑的一部分,用于在处理后将客户端重定向到另一个URL。
在第26行:设置"Access-Control-Allow-Origin"头,替换为"false",以确保不会替换现有值。
第27行:重新设置"Location"响应头为"http://www.example.com/tenant/oauth2/v2.0/authorize"。
"Access-Control-Allow-Origin"是CORS(跨源资源共享)头,我认为这是一个跨源请求问题。浏览器通常对网络请求应用同源限制。这些限制将阻止恶意页面在脚本内部进行跨源请求。例如,这意味着通常情况下从https://www.example.com提供的脚本不能向https://login.microsoftonline.com发出请求。
关于跨源资源共享,您可以通过以下链接了解更多信息:
"Access-Control-Allow-Origin"头是如何工作的
英文:
I carefully read the FRT logs you provided.
On line 13, after the URL rewrite, the request URL is now "http://localhost:5000/oauth/", which means the rewrite was successful.
On line 25: Set the "Location" response header to "https://login.microsoftonline.com/tenant/oauth2/v2.0/authorize". This could be part of application logic that redirects the client to another URL after processing.
On line 26: Set the "Access-Control-Allow-Origin" header , Replace="false", so the existing value will not be replaced.
Line 27: Re-set the "Location" response header to " http://www.example.com/tenant/oauth2/v2.0/authorize ".
"Access-Control-Allow-Origin" is a CORS (Cross-Origin Resource Sharing) header, I think is a cross-origin request issue. Browsers typically apply same-origin restrictions to network requests. These restrictions will prevent malicious pages from making cross-origin requests from within scripts. For example, this means ordinarily a script served from https://www.example.com cannot make a request to https://login.microsoftonline.com.
For cross-origin resource sharing, you can learn more about it through the link below:
答案2
得分: 0
这是IIS的应用请求路由功能的一部分。在“服务器代理设置”下取消选中“在响应标头中反向重写主机”解决了该问题。
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论