Skip to content Skip to sidebar Skip to footer

"typeerror: Argument 1 Must Be Str, Not None" When Running Flask-kerberos

I am trying to run the Flask-Kerberos example with a valid keytab file (it works with WSGI-Kerberos). Here is the content of my 'example.py' file from flask import Flask from flask

Solution 1:

I started with brutally integrating the Flask-Kerberos code directly into my 'example.py' file and using some print()s:

"""HERE GOES THE CONTENT OF flask_kerberos.py"""import kerberos
from flask import Response
from flask import _request_ctx_stack as stack
from flask import make_response
from flask import request
from functools import wraps
from socket import gethostname
from os import environ

_SERVICE_NAME = None#_SERVICE_NAME = 'HTTP/l.s.d'definit_kerberos(app, service='HTTP', hostname=gethostname()):
    '''
    Configure the GSSAPI service name, and validate the presence of the
    appropriate principal in the kerberos keytab.

    :param app: a flask application
    :type app: flask.Flask
    :param service: GSSAPI service name
    :type service: str
    :param hostname: hostname the service runs under
    :type hostname: str
    '''global _SERVICE_NAME
    _SERVICE_NAME = "%s@%s" % (service, hostname)
    print(_SERVICE_NAME) #HTTP@Server.l.s.dif'KRB5_KTNAME'notin environ:
        app.logger.warn("Kerberos: set KRB5_KTNAME to your keytab file")
    else:
        try:
            principal = kerberos.getServerPrincipalDetails(service, hostname)
        except kerberos.KrbError as exc:
            app.logger.warn("Kerberos: %s" % exc.message[0])
        else:
            app.logger.info("Kerberos: server is %s" % principal)


def_unauthorized():
    '''
    Indicate that authentication is required
    '''return Response('Unauthorized', 401, {'WWW-Authenticate': 'Negotiate'})


def_forbidden():
    '''
    Indicate a complete authentication failure
    '''return Response('Forbidden', 403)


def_gssapi_authenticate(token):
    '''
    Performs GSSAPI Negotiate Authentication

    On success also stashes the server response token for mutual authentication
    at the top of request context with the name kerberos_token, along with the
    authenticated user principal with the name kerberos_user.

    @param token: GSSAPI Authentication Token
    @type token: str
    @returns gssapi return code or None on failure
    @rtype: int or None
    '''
    state = None
    ctx = stack.top
    try:
        rc, state = kerberos.authGSSServerInit(_SERVICE_NAME)
        if rc != kerberos.AUTH_GSS_COMPLETE:
            returnNone
        rc = kerberos.authGSSServerStep(state, token)
        if rc == kerberos.AUTH_GSS_COMPLETE:
            ctx.kerberos_token = kerberos.authGSSServerResponse(state)
            ctx.kerberos_user = kerberos.authGSSServerUserName(state)
            return rc
        elif rc == kerberos.AUTH_GSS_CONTINUE:
            return kerberos.AUTH_GSS_CONTINUE
        else:
            returnNoneexcept kerberos.GSSError:
        returnNonefinally:
        if state:
            kerberos.authGSSServerClean(state)


defrequires_authentication(function):
    '''
    Require that the wrapped view function only be called by users
    authenticated with Kerberos. The view function will have the authenticated
    users principal passed to it as its first argument.

    :param function: flask view function
    :type function: function
    :returns: decorated function
    :rtype: function
    '''    @wraps(function)defdecorated(*args, **kwargs):
        header = request.headers.get("Authorization")
        if header:
            ctx = stack.top
            token = ''.join(header.split()[1:])
            rc = _gssapi_authenticate(token)
            if rc == kerberos.AUTH_GSS_COMPLETE:
                response = function(ctx.kerberos_user, *args, **kwargs)
                response = make_response(response)
                if ctx.kerberos_token isnotNone:
                    response.headers['WWW-Authenticate'] = ' '.join(['negotiate',
                                                                     ctx.kerberos_token])
                return response
            elif rc != kerberos.AUTH_GSS_CONTINUE:
                return _forbidden()
        return _unauthorized()
    return decorated

"""END OF THE flask_kerberos.py"""from flask import Flask
from flask import render_template
from config import Config

app = Flask(__name__)
app.config.from_object(Config)


@app.route("/")@requires_authenticationdefindex(user):
    return render_template('index.html', user=user)


if __name__ == '__main__':
    init_kerberos(app, hostname='Server.l.s.d')
    app.run()

As was mentioned in this answer:

The problem is exactly as the error message states - you've told the kerberos library to get a service principal from the keytab, but the keytab doesn't contain an entry for that service principal.

So, I decided to check several variables and their values, i.e. _SERVICE_NAME and getServerPrincipalDetails(service, hostname).

Firstly I set the _SERVICE_NAME='L.S.D' and after I got the 'Forbidden' response in my Browser. And here is an output in the CMD:

(venv) Server@User:~/.../flask_kerberos_example$ flask run

 * Serving Flask app "example.py" (lazy loading)
 * Environment: development
 * Debug mode: on
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 417-811-792
a.b.c.d - - [06/Jul/202111:01:06] "GET / HTTP/1.1"401 -
a.b.c.d - - [06/Jul/202111:01:06] "GET / HTTP/1.1"403 -

I run the the above code via Vim I received this message:

Traceback (most recent calllast):
  File "example.py", line 34, in init_kerberos
    principal = kerberos.getServerPrincipalDetails(service, hostname)
kerberos.KrbError: ('Cannot get sequence cursor from keytab', 2)

During handling of the above exception, another exception occurred:

Traceback (most recent calllast):
  File "example.py", line 140, in<module>
    init_kerberos(app)
  File "example.py", line 36, in init_kerberos
    app.logger.warn("Kerberos: %s" % exc.message[0])
AttributeError: 'KrbError' object has no attribute 'message'

shell returned 1

This issue brought me further to this issue on the GitHub. Where author stated:

Nevermind, regardless of how I interpret the code it works fine with service="HTTP" and hostname="my.host.name".

Therefore, I tried to adjust service and hostname variables of the getServerPrincipalDetails(service, hostname) function. The most convenient way for me to test it was:

import kerberos

service = 'HTTP'
hostname = 'Server.l.s.d'try:
    principal = kerberos.getServerPrincipalDetails(service, hostname)
except kerberos.KrbError as exc:
    print("Kerberos: %s" % exc.message[0])
else:
    print("Kerberos: server is %s" % principal)

So, I ended up with the following variables and their values

_SERVICE_NAME = None
service = 'HTTP'hostname = 'Server.l.s.d'

And after I got the response in Browser

Flask Kerberos Example

It worked, I think you are username@L.S.D.

and in CMD correspondingly

HTTP@Server.l.s.d
 * Serving Flask app "example" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
a.b.c.d - - [08/Jul/202113:02:18] "GET / HTTP/1.1"401 -
a.b.c.d - - [08/Jul/202113:02:18] "GET / HTTP/1.1"200 -
a.b.c.d - - [08/Jul/202113:02:18] "GET /static/style.css HTTP/1.1"304 -

Unfortunatelly it still does not work via flask run. It was asked as a new question here: Flask-Kerberos yields different results when running the code via "flask run" and with Vim

Post a Comment for ""typeerror: Argument 1 Must Be Str, Not None" When Running Flask-kerberos"