REMOTE_USER / SSO with kerberos

I’m back again looking at SSO. I had some kind of SSO working in the past, but
got sidetracket when working on the pi-admin tool.

Finally I tried to enable the webui policy again:

{ "user_details": true, "remote_user": "allowed", "login_mode": "privacyIDEA", "logout_time": "3600" } 

What I seem to miss is, what Location do I need to protect with Kerberos?

<Location /\#/login>
  SSLRequireSSL
  AuthType Kerberos
  AuthName "Kerberos Login"
  KrbMethodNegotiate On
  KrbMethodK5Passwd On
  KrbAuthRealms EXAMPLE.ORG
  Krb5KeyTab /etc/apache2/http.keytab
  KrbSaveCredentials On
  #KrbServiceName HTTP
  RequestHeader set REMOTE-USER %{REMOTE_USER}s
  require valid-user
</Location>

I know that I got the login with “authenticate with REMOTE_USER”, but
right now I’m lost. Apache Logs show that the Location protected has the
user, bit right now I#m lost where to lokk further.
Is anybody else using basic auth and can share the configuration?

Hi Jochen,

I am not using basic auth myself. I think it should be located at /auth.
This is where the remote_user is checked and if successful the JWT is issued. Please note, that you also need to set the REMOTE_USER policy.

Kind regards
Cornelius

Hm, /auth… If I trace the first call the privacyidea, we call the following URLs (others are cached):

GET / HTTP/1.1
GET /static/components/config/controllers/system.addons.js HTTP/1.1
GET /register HTTP/1.1

So, there is no call to /auth. I’ve again used / as the location - no change, not REMOTE_USER login.

Then I rechecked my policies - I had REMOTE_USER allowed for every realm,
but we need a policy with no realm selected - on that screen we don’t have a
realm yet. I’ll add some remarks to the documentation.

After that I get the familiar screen for REMOTE_USER. So I’m back to where
I left some time ago. Basically we can’t protect all URLs - so what’s the best way forward?

From my understanding of https://www.freeipa.org/page/Web_App_Authentication/Example_setup#Kerberos
the recommended implementation for Kerberos would be something like that:

  1. user calls http://privacyidea.example.org
  2. if privacyidea is configured for basic auth/REMOTE_USER, redirect to something like /login-sso (or whatever). If not, just use the regular login page.
  3. If the user has a ticket, display our current screen for REMOTE_USER, if not, redirect to the normal login page.
  4. user is logged in and can use privacyidea.

Do you think that would be a viable approach? I tried to find places to hack into the login process, but I didn’t see where I might start. Do you have a hint where in the source something like the above need to be added?

Thanks for your hints.

Hi Jochen,

to sum things up:

For basic auth to work with the WeUI you need to

  1. define a Web_UI/REMOTE_USER policy without realms.
  2. require basic authentication for certain paths

Require basic authentication for certain path

You need to define, that basic authentication should be requested. This needs to be defined in the webserver.
The REMOTE_USER policy then assures, that the user, which is passed in the HTTP header is used for getting a JWT token from privacyIDEA.
The tricky thing with the basic authentication is, that not all URLs of the privacyIDEA server need basic auth. E.g.

  • /validate/check
  • /ttype/…

need to be excluded.

It seems that it is a good idea to do this in Apache this way:
(In my case privacyIDEA is running in the sub path /pi)

    WSGIScriptAlias /pi      /etc/privacyidea/privacyideaapp.wsgi
    <Location /pi>
            AuthType Basic
            AuthName "privacyIDEA WebUI Auth"
            AuthBasicProvider file
            AuthUserFile "/etc/privacyidea/htpasswd"

            <RequireAny>
                # Either we need a URL with no authentication or we need a valid user
                <RequireAny>
                    # Any of these URL do NOT need a basic authentication
                    Require expr %{REQUEST_URI} =~ m#^/pi/validate#
                    Require expr %{REQUEST_URI} =~ m#^/pi/ttype#
                </RequireAny>
                Require valid-user
            </RequireAny>
    </Location>

So if you access any resource now, you are redirected to this login page:

Hope this helps.

Kind regards
Cornelius

That configuration looks better than what I have and we have in privacyidea’s docs.
I’ll try and probably update the docs.

I think I found the right place to implement this in webui/login.py.
I’ve changed the function called for “/” to:

# if we have remote_user allowed, call jk/basic-auth
@login_blueprint.route('/', methods=['GET'])
def login_switch():
    instance = request.script_root
    if instance == "/":
        instance = ""
    # The backend URL should come from the configuration of the system.
    backend_url = ""

    if current_app.config.get("PI_UI_DEACTIVATED"):
        # Do not provide the UI
        return render_template("deactivated.html")

    # check if login with REMOTE_USER is allowed.
    remote_user = ""
    password_reset = False
    if not hasattr(request, "all_data"):
        request.all_data = {}
    policy_object = PolicyClass()
    realms = ""
    client_ip = request.access_route[0] if request.access_route else \
        request.remote_addr

    try:
        # if is_remote_user_allowed(request):
        ruser_active = policy_object.get_action_values(ACTION.REMOTE_USER,
                                                       scope=SCOPE.WEBUI,
                                                         client=client_ip)

        if ruser_active:
            return redirect('/basic-auth')
    except HSMException:
        hsm_ready = False

    return redirect('/login-app')

The old function is now routed twice:

@login_blueprint.route('login-app', methods=['GET'])
@login_blueprint.route('basic-auth', methods=['GET'])
def login_user():

But now we don’t find some templates/static files, e.g.

404 "GET /basic-auth/static/components/login/views/login.html
404 "GET /basic-auth/static/components/login/views/login.html

Let’s see what I find out. It get’s better with staric_folder added:

login_blueprint = Blueprint('login_blueprint', __name__,static_folder='/static')

But I still get a 404:

https://pi/login-app/static/components/login/views/login.html

So there’s still a relative path in play.

What behaviour do you want to achieve?
Looks like you want to create your own path, to get the basic authentication?

What is the problem with the current implementation?

Right now there are two kinds of users logging in:

  1. With a Kerberos ticket: Gets the selection screen to use REMOTE_USER or choose other credentials

  2. Without a Kerberos ticket: Browser asks for credential (no theming etc.)
    a. correct Kerberos credentials -> selection screen
    b. no Kerberos credentials -> Unauthorized
    This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn’t understand how to supply the credentials required.

That’s not really user friendly. What I’d like to see ist:

  1. With a Kerberos ticket: Gets the selection screen to use REMOTE_USER or choose other credentials
  2. Without a Kerberos ticket: normal login from privacyidea (no browser box)

I got somewhat further with the following options in the apache config:

RewriteRule ^/basic-auth/auth/(.*)     /auth/$1 [PT]
RewriteRule ^/basic-auth/register/(.*)     /register/$1 [PT]
RewriteRule ^/basic-auth/statc/(.*)     /static/$1 [PT]
RewriteRule ^/login-app/auth/(.*)     /auth/$1 [PT]
RewriteRule ^/login-app/register/(.*)     /register/$1 [PT]
RewriteRule ^/login-app/statc/(.*)     /static/$1 [PT]

and

login_blueprint = Blueprint('login_blueprint', __name__,
                        static_folder='/static',template_folder=1'/static')

I finally got a login/selection screen - but a click just does nothing.
login just was not designed to live under another URL. Let’s see
if I can tackle that one too.