Authelia: Authelia - Basic Auth does not work with Backbox-Exporter

Created on 18 Feb 2019  路  7Comments  路  Source: authelia/authelia

Dear clems4ever,

````
{
"kind": "Ingress",
"apiVersion": "extensions/v1beta1",
"metadata": {
"name": "kibana",
"namespace": "logging",
"annotations": {
"ingress.kubernetes.io/auth-signin": "https://login-dev.example.com",
"ingress.kubernetes.io/auth-url": "https://login-dev.example.com/api/verify",
"ingress.kubernetes.io/force-ssl-redirect": "false",
"ingress.kubernetes.io/proxy-buffer-size": "256k",
"ingress.kubernetes.io/ssl-redirect": "false",
"kubernetes.io/ingress.class": "nginx"
}
},
"spec": {
"rules": [
{
"host": "kibana-dev-ops.example.com",
"http": {
"paths": [
{
"path": "/",
"backend": {
"serviceName": "kibana",
"servicePort": 5601
}
}
]
}
}
]
}
}

````

my ingress is configured as seen here.

````

#

Authelia configuration

#

The port to listen on

port: 8080

Log level

#

Level of verbosity for logs

logs_level: debug

Default redirection URL

#

If user tries to authenticate without any referer, Authelia

does not know where to redirect the user to at the end of the

authentication process.

This parameter allows you to specify the default redirection

URL Authelia will use in such a case.

#

Note: this parameter is optional. If not provided, user won't

be redirected upon successful authentication.

default_redirection_url: https://home.example.com:8080/

TOTP Issuer Name

#

This will be the issuer name displayed in Google Authenticator

See: https://github.com/google/google-authenticator/wiki/Key-Uri-Format for more info on issuer names

totp:
issuer: login-dev.example.com

The authentication backend to use for verifying user passwords

and retrieve information such as email address and groups

users belong to.

#

There are two supported backends: ldap and file.

authentication_backend:
ldap:
# The url of the ldap server
url: ldaps://LDAPURL:636

# The base dn for every entries
base_dn: BASEDN

# An additional dn to define the scope to all users
additional_users_dn: ou=People

# The users filter used to find the user DN
# {0} is a matcher replaced by username.
# 'cn={0}' by default.
users_filter: uid={0}

# An additional dn to define the scope of groups
additional_groups_dn: ou=Groups

# The groups filter used for retrieving groups of a given user.                                                                                                                                                                [136/9221]
# {0} is a matcher replaced by username.
# {dn} is a matcher replaced by user DN.
# 'member={dn}' by default.
groups_filter: (&(memberUid={0})(objectclass=posixGroup))

# The attribute holding the name of the group
group_name_attribute: cn

# The attribute holding the mail address of the user
mail_attribute: mail

# The username and password of the admin user.
user: LDAPUSER
password: LDAPPASSWORD

Access Control

#

Access control is a list of rules defining the authorizations applied for one

resource to users or group of users.

#

If 'access_control' is not defined, ACL rules are disabled and the bypass

rule is applied, i.e., access is allowed to anyone. Otherwise restrictions follow

the rules defined.

#

Note: One can use the wildcard * to match any subdomain.

It must stand at the beginning of the pattern. (example: *.mydomain.com)

#

Note: You must put patterns containing wildcards between simple quotes for the YAML

to be syntaxically correct.

#

Definition: A rule is an object with the following keys: domain, subject,

policy and resources.

#

- domain defines which domain or set of domains the rule applies to.

#

- subject defines the subject to apply authorizations to. This parameter is

optional and matching any user if not provided. If provided, the parameter

represents either a user or a group. It should be of the form 'user:'

or 'group:'.

#

- policy is the policy to apply to resources. It must be either bypass,

one_factor, two_factor or deny.

#

- resources is a list of regular expressions that matches a set of resources to

apply the policy to. This parameter is optional and matches any resource if not

provided.

#

Note: the order of the rules is important. The first policy matching

(domain, resource, subject) applies.

access_control:
# Default policy can either be bypass, one_factor, two_factor or deny.
# It is the policy applied to any resource if there is no policy to be applied
# to the user.
default_policy: deny

rules: [68/9221]
# Rules applied to everyone
- domain: '*.example.com'
policy: one_factor

- domain: single_factor.example.com

policy: one_factor

# Rules applied to 'admin' group

- domain: 'mx2.mail.example.com'

subject: 'group:admin'

policy: deny

- domain: '*.example.com'

subject: 'group:admin'

policy: two_factor

# Rules applied to 'dev' group

- domain: dev.example.com

resources:

- '^/groups/dev/.*$'

subject: 'group:dev'

policy: two_factor

# Rules applied to user 'john'

- domain: dev.example.com

resources:

- '^/users/john/.*$'

subject: 'user:john'

policy: two_factor

# Rules applied to user 'harry'

- domain: dev.example.com

resources:

- '^/users/harry/.*$'

subject: 'user:harry'

policy: two_factor

# Rules applied to user 'bob'

- domain: '*.mail.example.com'

subject: 'user:bob'

policy: two_factor

- domain: 'dev.example.com'

resources:

- '^/users/bob/.*$'

subject: 'user:bob'

policy: two_factor

Configuration of session cookies

#

The session cookies identify the user once logged in.

session:
# The name of the session cookie. (default: authelia_session).
name: authelia_session

# The secret to encrypt the session cookie.
secret: SESSIONSECRET

# The time in ms before the cookie expires and session is reset.
expiration: 3600000 # 1 hour

# The inactivity time in ms before the session is reset.
inactivity: 3600000 # 1 hour

# The domain to protect.
# Note: the authenticator must also be in that domain. If empty, the cookie
# is restricted to the subdomain of the issuer.
domain: example.com

# The redis connection details
redis:
host: authelia-redis-master
port: 6379
password: REDISPASSWORD

Configuration of the authentication regulation mechanism.

#

This mechanism prevents attackers from brute forcing the first factor.

It bans the user if too many attempts are done in a short period of

time.

regulation:
# The number of failed login attempts before user is banned.
# Set it to 0 to disable regulation.
max_retries: 3

# The time range during which the user can attempt login before being banned.
# The user is banned if the authenticaction failed max_retries times in a find_time seconds window.
find_time: 120

# The length of time before a banned user can login again.
ban_time: 300

Configuration of the storage backend used to store data and secrets.

#

You must use only an available configuration: local, mongo

storage:
# The directory where the DB files will be saved
## local:
## path: /var/lib/authelia/store

# Settings to connect to mongo server
mongo:
url: mongodb://mongo-0.mongo:27017,mongo-1.mongo:27017,mongo-2.mongo:27017/?replicaSet=rs0
database: authelia
auth:
username: MONGOUSER
password: MONGOPASSWORD

Configuration of the notification system.

#

Notifications are sent to users when they require a password reset, a u2f

registration or a TOTP registration.

Use only an available configuration: filesystem, gmail

notifier:
# For testing purpose, notifications can be sent in a file
## filesystem:
## filename: /tmp/authelia/notification.txt

# Use your email account to send the notifications. You can use an app password.
# List of valid services can be found here: https://nodemailer.com/smtp/well-known/
## email:
## username: [email protected]
## password: yourpassword
## sender: [email protected]
## service: gmail

# Use a SMTP server for sending notifications
smtp:
#username: test
#password: password
secure: false
host: 'SMTPHOST'
port: 25
sender: EMAIL

````

The login is working in the browser (great job!). But not the probing against Authelia with BasicAuth.

Do You require a specific nginx version?
What could be the reason?

P2 Question

Most helpful comment

Hi @clems4ever,

we figured out that the problem was at the Nginx Ingress Controller in Kubernetes.

There are two settings in the Nginx Ingress Controller we have to configure in the official Helm-Chart (https://github.com/helm/charts/tree/master/stable/nginx-ingress).

With Nginx Ingress Controller > 0.21.0 we have to set:

    controller:
      config:
        proxy-real-ip-cidr: "0.0.0.0/0"
        use-forwarded-headers: "true"
      headers:
        Proxy-Authorization: $http_authorization

With Nginx Ingress Controller <= 0.21.0 we only have to set:

    controller:
      headers:
        Proxy-Authorization: $http_authorization

Now basic-auth with Nginx Ingress Controller in Kubernetes is working as expected.

Thank you for the great work.

All 7 comments

Hello @RafalMaleska , I don't see anything weird in your conf. Can you extract some logs?

Hi @clems4ever , just wanted to provide more information.

As @RafalMaleska said, the login (with LDAP credentials) is working via browser perfectly.
For some cases we need basic auth. For example with curl (or blackbox exporter is also working with basic auth):

curl -u ldapuser https://some-app.example.com

This results in:

<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
<hr><center>nginx/1.13.8</center>
</body>
</html>

A curl with -L (follow redirects)
curl -L -u ldapuser https://some-app.example.com
results in:

<!DOCTYPE html><html><head><title>Authelia - 2FA</title><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="robots" content="noindex, nofollow, nosnippet, noarchive"><meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src 'self' data:;"><link rel="icon" href="/img/icon.png" type="image/png" sizes="32x32"><link rel="stylesheet" type="text/css" href="/css/authelia.css"></head><body><div class="container"><div class="row"><div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 col-lg-6 col-lg-offset-3"><div class="account-wall firstfactor"><div class="row header"><h1>Sign in</h1></div><div class="row body"><div class="form col-xs-10 col-xs-offset-1 col-sm-8 col-sm-offset-2 col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2"><div class="notification"></div><img class="header-img" src="/img/user.png" alt="user profile"><p>Enter your credentials to sign in</p><form class="form-signin"><div class="form-inputs"><input class="form-control" type="text" id="username" placeholder="Username" required autofocus><input class="form-control" type="password" id="password" placeholder="Password" required></div><button class="btn btn-lg btn-primary btn-block" id="signin" type="submit">Sign in</button><div class="keep-me-logged-in pull-left"><input type="checkbox" id="keep_me_logged_in" name="keep_me_logged_in" value="true"><label for="keep_me_logged_in">Keep me logged in</label></div><div class="bottom-right-links pull-right"><a class="link forgot-password" href="/password-reset/request">Forgot password?</a></div><span class="clearfix"></span></form></div></div><div class="row footer poweredby-block"><div class="poweredby col-xs-6 col-xs-offset-4 col-sm-6 col-sm-offset-4 col-md-6 col-md-offset-4">Powered by <a class="authelia-brand" href="https://github.com/clems4ever/authelia">Authelia</a></div></div></div></div></div></div><script src="/js/authelia.js" type="text/javascript"></script></body></html>%

These curl calls produce the following authelia logs:

debug: date='Tue Mar 05 2019 12:12:27 GMT+0000 (UTC)' method='GET', path='/api/verify' requestId='90342486-eddb-4520-b48d-5b9fbb1aa3a6' sessionId='u0h5nwD_fHMF4hYorUqJBDuEVIT_aayt' ip='10.9.104.217' message='Headers = {"host":"login-dev.example.com","connection":"close","x-real-ip":"10.9.104.217","x-forwarded-for":"10.9.104.217","x-forwarded-host":"login-dev.example.com","x-forwarded-port":"443","x-forwarded-proto":"https","x-original-uri":"/api/verify","x-scheme":"https","x-original-forwarded-for":"10.9.104.217, 10.43.151.201","accept-encoding":"gzip","user-agent":"Go-http-client/1.1","x-auth-request-redirect":"/","x-original-method":"GET","x-original-url":"http://some-app.example.com/","x-sent-from":"nginx-ingress-controller"}'
debug: date='Tue Mar 05 2019 12:12:27 GMT+0000 (UTC)' method='GET', path='/api/verify' requestId='90342486-eddb-4520-b48d-5b9fbb1aa3a6' sessionId='u0h5nwD_fHMF4hYorUqJBDuEVIT_aayt' ip='10.9.104.217' message='Authentication session u0h5nwD_fHMF4hYorUqJBDuEVIT_aayt was undefined. Resetting.'
error: date='Tue Mar 05 2019 12:12:27 GMT+0000 (UTC)' method='GET', path='/api/verify' requestId='90342486-eddb-4520-b48d-5b9fbb1aa3a6' sessionId='u0h5nwD_fHMF4hYorUqJBDuEVIT_aayt' ip='10.9.104.217' message='Reply with error 401: userid is missing'
debug: date='Tue Mar 05 2019 12:12:27 GMT+0000 (UTC)' method='GET', path='/api/verify' requestId='90342486-eddb-4520-b48d-5b9fbb1aa3a6' sessionId='u0h5nwD_fHMF4hYorUqJBDuEVIT_aayt' ip='10.9.104.217' message='AccessDeniedError: userid is missing
    at BluebirdPromise.resolve.then (/usr/src/server/src/lib/routes/verify/get_session_cookie.js:31:43)
    at tryCatcher (/usr/src/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/usr/src/node_modules/bluebird/js/release/promise.js:512:31)
    at Promise._settlePromise (/usr/src/node_modules/bluebird/js/release/promise.js:569:18)
    at Promise._settlePromiseCtx (/usr/src/node_modules/bluebird/js/release/promise.js:606:10)
    at _drainQueueStep (/usr/src/node_modules/bluebird/js/release/async.js:142:12)
    at _drainQueue (/usr/src/node_modules/bluebird/js/release/async.js:131:9)
    at Async._drainQueues (/usr/src/node_modules/bluebird/js/release/async.js:147:5)
    at Immediate.Async.drainQueues (/usr/src/node_modules/bluebird/js/release/async.js:17:14)
    at runCallback (timers.js:785:20)
    at tryOnImmediate (timers.js:747:5)
    at processImmediate [as _immediateCallback] (timers.js:718:5)'

Do you have any ideas?

Hello @RafalMaleska and @dbluxo , I found what's causing your issue. It's because the authorization header to log in basic auth is not Authorization but Proxy-Authorization instead. You need something like
curl -H "Proxy-Authorization: Basic XXXXXXXXXX" https://some-app.example.com.

https://github.com/clems4ever/authelia/blob/f8a12b8482c3a013697e0ed2b616b7fd277146db/server/src/lib/routes/verify/get.ts#L24
https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#Proxy_authentication

What you can do is rewrite the header in nginx to transform Authorization to Proxy-Authorization before sending the query to Authelia.

I'll add more logs in Authelia to make this problem clearer and I'll close the issue afterwards.

Hello @RafalMaleska , @dbluxo , did it solve your issue?

Hi @clems4ever,

we have tried it as you suggested, but without success:
curl -L -H "Proxy-Authorization: Basic XXXXXXXXXXX" https://some-app.example.com

This results in:

<!DOCTYPE html><html><head><title>Authelia - 2FA</title><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="robots" content="noindex, nofollow, nosnippet, noarchive"><meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src 'self' data:;"><link rel="icon" href="/img/icon.png" type="image/png" sizes="32x32"><link rel="stylesheet" type="text/css" href="/css/authelia.css"></head><body><div class="container"><div class="row"><div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 col-lg-6 col-lg-offset-3"><div class="account-wall firstfactor"><div class="row header"><h1>Sign in</h1></div><div class="row body"><div class="form col-xs-10 col-xs-offset-1 col-sm-8 col-sm-offset-2 col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2"><div class="notification"></div><img class="header-img" src="/img/user.png" alt="user profile"><p>Enter your credentials to sign in</p><form class="form-signin"><div class="form-inputs"><input class="form-control" type="text" id="username" placeholder="Username" required autofocus><input class="form-control" type="password" id="password" placeholder="Password" required></div><button class="btn btn-lg btn-primary btn-block" id="signin" type="submit">Sign in</button><div class="keep-me-logged-in pull-left"><input type="checkbox" id="keep_me_logged_in" name="keep_me_logged_in" value="true"><label for="keep_me_logged_in">Keep me logged in</label></div><div class="bottom-right-links pull-right"><a class="link forgot-password" href="/password-reset/request">Forgot password?</a></div><span class="clearfix"></span></form></div></div><div class="row footer poweredby-block"><div class="poweredby col-xs-6 col-xs-offset-4 col-sm-6 col-sm-offset-4 col-md-6 col-md-offset-4">Powered by <a class="authelia-brand" href="https://github.com/clems4ever/authelia">Authelia</a></div></div></div></div></div></div><script src="/js/authelia.js" type="text/javascript"></script></body></html>

The curl call produce the following authelia logs:

debug: date='Tue Mar 12 2019 09:16:21 GMT+0000 (UTC)' method='GET', path='/api/verify' requestId='292f8a43-60fc-40c8-9769-15b987f9eb61' sessionId='Q1__Rs-spKnLFe46xxdkJkuUxs-58FOM' ip='10.43.151.32' message='Headers = {"host":"login-dev.example.com","connection":"close","x-real-ip":"10.43.151.32","x-forwarded-for":"10.43.151.32","x-forwarded-host":"login-dev.example.com","x-forwarded-port":"443","x-forwarded-proto":"https","x-original-uri":"/api/verify","x-scheme":"https","x-original-forwarded-for":"10.43.151.32, 10.43.150.121","x-amzn-trace-id":"Self=1-5c8778e5-73821c0e1016c14e29430f1a;Root=1-5c8778e5-8b4336d01b1b9a584d6dee68","x-original-url":"http://some-app.example.com/","x-original-method":"GET","x-sent-from":"nginx-ingress-controller","x-auth-request-redirect":"/","user-agent":"curl/7.61.1","accept":"*/*"}'
debug: date='Tue Mar 12 2019 09:16:21 GMT+0000 (UTC)' method='GET', path='/api/verify' requestId='292f8a43-60fc-40c8-9769-15b987f9eb61' sessionId='Q1__Rs-spKnLFe46xxdkJkuUxs-58FOM' ip='10.43.151.32' message='Authentication session Q1__Rs-spKnLFe46xxdkJkuUxs-58FOM was undefined. Resetting.'
error: date='Tue Mar 12 2019 09:16:21 GMT+0000 (UTC)' method='GET', path='/api/verify' requestId='292f8a43-60fc-40c8-9769-15b987f9eb61' sessionId='Q1__Rs-spKnLFe46xxdkJkuUxs-58FOM' ip='10.43.151.32' message='Reply with error 401: userid is missing'
debug: date='Tue Mar 12 2019 09:16:21 GMT+0000 (UTC)' method='GET', path='/api/verify' requestId='292f8a43-60fc-40c8-9769-15b987f9eb61' sessionId='Q1__Rs-spKnLFe46xxdkJkuUxs-58FOM' ip='10.43.151.32' message='AccessDeniedError: userid is missing
    at BluebirdPromise.resolve.then (/usr/src/server/src/lib/routes/verify/get_session_cookie.js:31:43)
    at tryCatcher (/usr/src/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/usr/src/node_modules/bluebird/js/release/promise.js:512:31)
    at Promise._settlePromise (/usr/src/node_modules/bluebird/js/release/promise.js:569:18)
    at Promise._settlePromiseCtx (/usr/src/node_modules/bluebird/js/release/promise.js:606:10)
    at _drainQueueStep (/usr/src/node_modules/bluebird/js/release/async.js:142:12)
    at _drainQueue (/usr/src/node_modules/bluebird/js/release/async.js:131:9)
    at Async._drainQueues (/usr/src/node_modules/bluebird/js/release/async.js:147:5)
    at Immediate.Async.drainQueues (/usr/src/node_modules/bluebird/js/release/async.js:17:14)
    at runCallback (timers.js:785:20)
    at tryOnImmediate (timers.js:747:5)
    at processImmediate [as _immediateCallback] (timers.js:718:5)'
debug: date='Tue Mar 12 2019 09:16:21 GMT+0000 (UTC)' method='GET', path='/' requestId='07d2bb25-6e1f-416f-a86f-6a61a8219a8c' sessionId='V9E86iWIPeNSbX-igDnXT84dDDQyUMvd' ip='10.43.151.32' message='Headers = {"host":"login-dev.example.com","connection":"close","x-real-ip":"10.43.151.32","x-forwarded-for":"10.43.151.32","x-forwarded-host":"login-dev.example.com","x-forwarded-port":"443","x-forwarded-proto":"https","x-original-uri":"/?rd=https://some-app.example.com/","x-scheme":"https","x-original-forwarded-for":"10.43.151.32","x-amzn-trace-id":"Root=1-5c8778e5-ee81ee28b7a6c317373cc391","user-agent":"curl/7.61.1","accept":"*/*"}'
debug: date='Tue Mar 12 2019 09:16:21 GMT+0000 (UTC)' method='GET', path='/' requestId='07d2bb25-6e1f-416f-a86f-6a61a8219a8c' sessionId='V9E86iWIPeNSbX-igDnXT84dDDQyUMvd' ip='10.43.151.32' message='Authentication session V9E86iWIPeNSbX-igDnXT84dDDQyUMvd was undefined. Resetting.'

We have deployed nginx-ingress-controller and all ingresses as you described in your example for kubernetes:
https://github.com/clems4ever/authelia/tree/master/example/kube

Any further ideas?

Hi @clems4ever,

we figured out that the problem was at the Nginx Ingress Controller in Kubernetes.

There are two settings in the Nginx Ingress Controller we have to configure in the official Helm-Chart (https://github.com/helm/charts/tree/master/stable/nginx-ingress).

With Nginx Ingress Controller > 0.21.0 we have to set:

    controller:
      config:
        proxy-real-ip-cidr: "0.0.0.0/0"
        use-forwarded-headers: "true"
      headers:
        Proxy-Authorization: $http_authorization

With Nginx Ingress Controller <= 0.21.0 we only have to set:

    controller:
      headers:
        Proxy-Authorization: $http_authorization

Now basic-auth with Nginx Ingress Controller in Kubernetes is working as expected.

Thank you for the great work.

Wow, interesting! I will certainly include this in a doc somewhere.
Thanks for giving back your investigation results!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

greenpau picture greenpau  路  4Comments

lued picture lued  路  3Comments

zjzeit picture zjzeit  路  3Comments

JulienSambre picture JulienSambre  路  10Comments

leveled picture leveled  路  7Comments