Nginx config: how to use auth_basic authentication if ssl_client_certificate none provided?
Asked Answered
C

5

21

I'm trying to set up Nginx server as follows:

First, the server should check whether the user provides the client SSL certificate (via ssl_client_certificate). If the SSL certificate is provided, then give access to the site,

If the SSL certificate is NOT provided, then ask the user to enter a password and logs through auth_basic.

I was able to configure both the authentication method at the same time. But this config is superfluous.

To make check, whether the user provides its SSL certificate I try the config like this:

18:    if ($ssl_client_verify != SUCCESS) {
19:        auth_basic "Please login";
20:        auth_basic_user_file .passfile;
21:    }

But Nginx returns an error:

"auth_basic" directive is not allowed here in .../ssl.conf:19

How can I to set the condition in this case?

Cleavage answered 17/5, 2014 at 22:15 Comment(1)
hi pavel, did you ever manage to do whta you wanted? i have quite the same problem...Wardell
P
34

You can set auth_basic configuration in the if clause like this:

server {
    listen 443;
    auth_basic_user_file    .htpasswd;
    ssl_client_certificate  ca.cert;
    ssl_verify_client       optional;
    ...

    location / {
      ...

      if ($ssl_client_verify = SUCCESS) {
        set $auth_basic off;
      }
      if ($ssl_client_verify != SUCCESS) {
        set $auth_basic Restricted;
      }

      auth_basic $auth_basic;
    }
}

Now, authentication falls back to HTTP Basic if no client certificate has been provided (or if validation failed).

Pawl answered 16/8, 2015 at 19:9 Comment(1)
Simplify: set $auth_basic Restricted; if ($ssl_client_verify = SUCCESS) {set $auth_basic off;}Ked
S
4

I'm unable to test this currently, but would something like this work?

server {
    listen 80;
    server_name www.example.com example.com;
    rewrite ^ https://$server_name$request_uri? permanent;
}
server {
    listen 443;
    ...

    if ($ssl_client_verify != SUCCESS) {
        rewrite ^ http://auth.example.com/ permanent;
    } 
    location / {
        ...
    }

}
server {
    listen 80;
    server_name auth.example.com;
    location / {
        auth_basic "Please login";
        auth_basic_user_file .passfile;
    }
} 

So basically:
- Accept all initial request (on port 80 for whatever name you're using) and rewrite to ssl
- Check if there's an the client is verified.
- If not, rewrite to an alternate domain that uses basic auth

Like I said, I can't test it right now, but I'll try to get around to it! Let me know if it helps, I'm interested to see if it works.

Schertz answered 13/1, 2015 at 16:15 Comment(1)
Curious about this, did you ever get it working? Did the above implementation work?Schertz
C
4

You may try using a map.

map $ssl_client_verify $var_auth_basic {
   default off;
   SUCCESS "Please login";
}

server {
   ....
   auth_basic $var_auth_basic;
   auth_basic_user_file .passfile;

that way the value depends on $ssl_client_verify but is alsa always defined and auth_basic and auth_basic_user_file is always inside server { block.

Coons answered 22/4, 2021 at 12:58 Comment(0)
C
3

Nginx provides no way to fall back to basic authentication when client cert fails. As an alternative you can use variables to restrict access:

location / { 
  if ($ssl_client_verify = "SUCCESS") {
    set $authorized 1;
  }
  if ($authorized != 1) {
    error_page 401 @basicauth;
    return 401;
  }
}

location @basicauth {
  auth_basic "Please login";
  auth_basic_user_file .passfile;
  set $authorized 1;
  rewrite /(.*) /$1;
}

*keep in mind that IfIsEvil and these rules may work incorrectly or interfere with other parts of a larger configuration.

Cannae answered 14/1, 2015 at 17:35 Comment(0)
W
2

Forget about it, it won't work.

The reason why it fails is because if is not part of the general configuration module as one should believe. if is part of the rewrite module and auth_basic is another module. You just cannot have dynamic vhosts with basic auth.

On the other hand...

You can have dynamic vhosts with their own error pages. The following example is designed for a custom 404 page but you can implement it into your code.

server {
    listen 80;
    server_name _;

    set $site_root /data/www/$host;

    location / {
        root $site_root;
    }

    error_page 404 =404 /404.html;

    location /404.html {
        root $site_root/error_files;
        internal;

        error_page 404 =404 @fallback_404;
    }

    location @fallback_404 {
        root /var/www/;
        try_files /404.html =404;
        internal;
    }

    error_log  /var/log/nginx/error.log  info;
    access_log  /var/log/nginx/access.log;
}

What happens...

  • you are telling Nginx to use /404.html in case of HTTP_NOT_FOUND.
  • changing the location root to match the Web site error_pages directory.
  • internal redirection
  • returning a 404 http code
  • configure the fallback 404 page in location @fallback_404: In this location, the root is changed to /var/www/ so it will read files from that path instead of $site_root
  • at the last stage the code returns /var/www/404.html if it exists with a 404 http code.

NOTE: According to Nginx documentation :

Specifies that a given location can only be used for internal requests. For external requests, the client error 404 (Not Found) is returned. Internal requests are the following:

  • requests redirected by the error_page, index, random_index, and try_files directives;
  • requests redirected by the “X-Accel-Redirect” response header field from an upstream server;
  • subrequests formed by the “include virtual” command of the ngx_http_ssi_module module and by the ngx_http_addition_module module directives;
  • requests changed by the rewrite directive.

Also:

There is a limit of 10 internal redirects per request to prevent request processing cycles that can occur in incorrect configurations. If this limit is reached, the error 500 (Internal Server Error) is returned. In such cases, the “rewrite or internal redirection cycle” message can be seen in the error log.

Check this link for more, hope that helps.

Wyoming answered 9/1, 2015 at 16:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.