0

I have Flask app on IIS similiar to this tutorial : https://medium.com/@nerdijoe/how-to-deploy-flask-on-iis-with-windows-authentication-733839d657b7 but I'm using httpPlatformHandler instead of FastCGI. With web.config as below I get None in REMOTE_USER :

request.environ.get('REMOTE_USER')

web.config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <handlers>
            <add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" requireAccess="Script" />
        </handlers>
        <httpPlatform stdoutLogEnabled="true" stdoutLogFile=".\python.log" startupTimeLimit="20" processPath="C:\python3\python.exe" arguments="-m flask run --port %HTTP_PLATFORM_PORT%">
        </httpPlatform>
        <httpErrors errorMode="DetailedLocalOnly" />
        <security>
            <authentication>
                <anonymousAuthentication enabled="false" />
                <windowsAuthentication enabled="true" />
            </authentication>
        </security>
    </system.webServer>
</configuration>

How to get username of a user logged to a site using Flask on IIS?

Lex Li
  • 60,503
  • 9
  • 116
  • 147
  • 1
    Does this answer your question? [How to get the authenticated user name in Python when fronting it with IIS HTTP PlatformHandler and using Windows auth?](https://stackoverflow.com/questions/62806295/how-to-get-the-authenticated-user-name-in-python-when-fronting-it-with-iis-http) – Lex Li Dec 21 '22 at 05:48
  • You coulld refer to [this answer](https://stackoverflow.com/questions/39627947/how-do-i-get-the-username-of-the-current-user-in-a-flask-app-on-an-iis-server-us) – TengFeiXie Dec 21 '22 at 07:20
  • 1
    @LexLi there is no "x-iis-windowsauthtoken" in request.headers.keys(). – t4kahiro Dec 29 '22 at 12:11
  • 1
    @TengFeiXie Yeah, but ISAPI_Rewrite is not free, "4. Helicon Tech grants permission to use ISAPI_Rewrite during a test period of 30-days. When the trial period is over you should either buy ISAPI_Rewrite or remove the ISAPI_Rewrite product." $99 so, its not for me. – t4kahiro Dec 29 '22 at 13:25
  • You need to ask HttpPlatformHandler to pass Windows Authentication token. Read the documentation please. – Lex Li Dec 29 '22 at 15:47

1 Answers1

0

web.config looks ok just need to add forwardWindowsAuthToken to httpPlatform config:

...
<httpPlatform stdoutLogEnabled="true"
              stdoutLogFile=".\python.log"
              startupTimeLimit="20"
              processPath="C:\python3\python.exe"
              arguments="-m flask run --port %HTTP_PLATFORM_PORT%"
              forwardWindowsAuthToken="true">
...

Then the header with the token will be present on the request that gets forwarded on, just need to extract it:

import win32api
import win32security

def get_username_from_token(token_handle: str):
    token_handle = int(token_handle, 16) # need to convert from Hex / base 16
    sid = win32security.GetTokenInformation(token_handle, 1)[0] # TOKEN_INFORMATION_CLASS enum value 1 = TokenUser
    username, domain, account_type = win32security.LookupAccountSid(None, sid)
    win32api.CloseHandle(token_handle) # to prevent resource leak
    return username

And then in your Flask app, assuming you are using Flask Login's LoginManager:

class User(UserMixin):
    def __init__(self, username):
        self.id = username


@login_manager.user_loader
def load_user(username):
    # normally here you would have a users table in a DB and can do a look up and return whatever User object you need
    # this func should return None if unknown User
    return User(username)


@login_manager.request_loader
def load_user_from_request(request):
    if os.getenv("FLASK_ENV", None) == "development":
        return load_user("USERNAME_TO_IMPERSONATE_DURING_DEVELOPMENT")
    # Note if using aspNetCore instead of original httpPlatformHandler then the header would be 'Ms-Aspnetcore-Winauthtoken' instead of 'X-IIS-WindowsAuthToken'
    # Also note that the header lookup is case-insensitive (for Flask at least, as in this example)
    token_handle_str = request.headers.get("X-IIS-WindowsAuthToken", None)
    if token_handle_str:
        try:
            username = get_username_from_token(token_handle_str)
            user = load_user(username)
            if user:
                log.info(f"Authorized user {username} is accessing the site.")
                return user
            else:
                log.warning(
                    f"Unauthorized user {username} attempted to access the site."
                )
        except Exception as e:
            log.error(e)

    return None
Mark Z.
  • 2,127
  • 16
  • 33