Für das Hosting einer Streamlit App über IIS als Proxy gibts eine fantastische Anleitung: https://gist.github.com/stanorama/bb52930e3cf70138d7f199338c064ae6, kurz zusammengefasst falls der Gist mal verschwinden sollte:

  • In der IIS Rolle WebSocket Protocol enablen
  • In der IIS Rolle Windows Authentication enablen
  • Application Request Routing installieren (https://www.iis.net/downloads/microsoft/application-request-routing) und in der IIS Console bei den Actions des Features in „Server Proxy Settings“ Proxy einschalten
  • URL Rewrite installieren (https://www.iis.net/downloads/microsoft/url-rewrite)
  • Die User Site erzeugen, gerne auch mit https
  • Windows Authentication auf die Site enablen und Provider auf nur NTLM umstellen (jaaaa, grausam), Site Directory ACL setzen oder in den Authentication Rules entsprechende Gruppen/User hinterlegen
  • URL Rewrite Regel (inbound) erzeugen mit Match URL = .* Rewrite auf http://localhost:1234/{R:0} (dort wo halt die Streamlist App läuft) erzeugen

Resultierende web.config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="Reverse proxy to streamlit application running on localhost">
                    <match url=".*" />
                    <action type="Rewrite" url="http://localhost:8511/{R:0}" />
                    <conditions>
                        <add input="{HTTP_HOST}" pattern=".*" />
                    </conditions>
                    <serverVariables>
                    </serverVariables>
                </rule>
            </rules>
        </rewrite>
        <security>
            <authentication>
                <windowsAuthentication enabled="true">
                    <providers>
                        <clear />
                        <add value="NTLM" />
                    </providers>
                </windowsAuthentication>
            </authentication>
        </security>
    </system.webServer>
    <system.web>
        <authorization>
            <allow roles="The_group_with_access" />
        </authorization>
    </system.web>
</configuration>

Im Home vom Streamlit App startenden User .streamlit Verzeichnis erzeugen und darin config.toml (sonst funktioniert WebSocket Weiterleitung nicht):

[server]
enableCORS = false
enableXsrfProtection = false

Streamlit App starten:

<pfad mit venv wo streamlist installiert ist>\streamlit.exe run C:\some_streamlist_app\app.py --server.headless true --server.port 8511 --browser.serverAddress localhost

In Anlehnung an https://gist.github.com/Chibitko/e5366851cf47b6fb238a49d6e0d37b94 zum Decodieren des NTLM Authorization Headers kann man st.context.headers["Authorization"] dieser Funktion übergeben und bekommt User, Domäne und Clientname geliefert:

VALID_CHRS = set(string.ascii_letters + string.digits + string.punctuation)
def clean_str(st):
    return ''.join((s if s in VALID_CHRS else '?') for s in st)

class StrStruct(object):
    def __init__(self, pos_tup, raw):
        length, alloc, offset = pos_tup
        self.length = length
        self.alloc = alloc
        self.offset = offset
        self.raw = raw[offset:offset+length]
        self.utf16 = False

        if len(self.raw) >= 2 and self.raw[1] == 0:
            self.string = self.raw.decode('utf-16')
            self.utf16 = True
        else:
            self.string = self.raw
        
    def __str__(self):
        return clean_str(self.string)


def decode_ntlmssp(header_raw):
    try:
        header = base64.b64decode(header_raw[5:])
    except:
        return "","",""

    if header[:8] != b"NTLMSSP\0":
        return "","",""

    ver_tup = struct.unpack("<i", header[8:12])
    ver = ver_tup[0]
    if ver != 3:
       return "","",""
    hdr_tup = struct.unpack("<hhihhihhihhihhi", header[12:52])

    domain=StrStruct(hdr_tup[6:9], header).string
    user=StrStruct(hdr_tup[9:12], header).string
    client=StrStruct(hdr_tup[12:15], header).string

    return client.upper(),domain.upper(),user.upper()