Merge pull request #166 from clems4ever/no-search-engine-indexing

- Add a meta tag to avoid search engine indexing
- Improve security with Content-Security-Policy
- Change basicauth.test.local into single_factor.test.local
pull/168/merge
Clément Michaud 2017-10-20 01:28:06 +02:00 committed by GitHub
commit 004a55ea2f
21 changed files with 107 additions and 324 deletions

View File

@ -17,7 +17,7 @@ addons:
hosts: hosts:
- admin.test.local - admin.test.local
- auth.test.local - auth.test.local
- basicauth.test.local - single_factor.test.local
- dev.test.local - dev.test.local
- home.test.local - home.test.local
- mx1.mail.test.local - mx1.mail.test.local

View File

@ -4,3 +4,4 @@ who commit code to the project are encouraged to add their names
here. Please keep the list sorted by first names here. Please keep the list sorted by first names
Clement Michaud <clement.michaud34@gmail.com> Clement Michaud <clement.michaud34@gmail.com>
Antoine Favre <@n4kre>

View File

@ -101,6 +101,7 @@ Add the following lines to your **/etc/hosts** to alias multiple subdomains so t
127.0.0.1 admin.test.local 127.0.0.1 admin.test.local
127.0.0.1 mx1.mail.test.local 127.0.0.1 mx1.mail.test.local
127.0.0.1 mx2.mail.test.local 127.0.0.1 mx2.mail.test.local
127.0.0.1 single_factor.test.local
127.0.0.1 auth.test.local 127.0.0.1 auth.test.local
### Run it! ### Run it!
@ -221,6 +222,28 @@ that the attacker must also require the certificate to retrieve the cookies.
Note that using [HSTS] has consequences. That's why you should read the blog Note that using [HSTS] has consequences. That's why you should read the blog
post nginx has written on [HSTS]. post nginx has written on [HSTS].
### More protections measures
You can also apply the following headers to your nginx configuration for
improving security. Please read the documentation of those headers before
applying them blindly.
```
# We don't want any credentials / TOTP secret key / QR code to be cached by
# the client
add_header Cache-Control "no-store";
add_header Pragma "no-cache";
# Clickjacking / XSS protection
# We don't want Authelia's login page to be rendered within a <frame>,
# <iframe> or <object> from an external website.
add_header X-Frame-Options "SAMEORIGIN";
# Block pages from loading when they detect reflected XSS attacks.
add_header X-XSS-Protection "1; mode=block";
```
## Documentation ## Documentation
### Authelia configuration ### Authelia configuration
The configuration of the server is defined in the file The configuration of the server is defined in the file

View File

@ -1,6 +1,6 @@
body { body {
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NiIgaGVpZ2h0PSIxMDAiPgo8cmVjdCB3aWR0aD0iNTYiIGhlaWdodD0iMTAwIiBmaWxsPSIjRkZGRkZGIj48L3JlY3Q+CjxwYXRoIGQ9Ik0yOCA2NkwwIDUwTDAgMTZMMjggMEw1NiAxNkw1NiA1MEwyOCA2NkwyOCAxMDAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI0ZDRkNGQyIgc3Ryb2tlLXdpZHRoPSIyIj48L3BhdGg+CjxwYXRoIGQ9Ik0yOCAwTDI4IDM0TDAgNTBMMCA4NEwyOCAxMDBMNTYgODRMNTYgNTBMMjggMzQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI0ZCRkJGQiIgc3Ryb2tlLXdpZHRoPSIyIj48L3BhdGg+Cjwvc3ZnPg=="); background-image: url("/img/background.svg");
} }
.authelia-brand { .authelia-brand {

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="56" height="100">
<rect width="56" height="100" fill="#FFFFFF"></rect>
<path d="M28 66L0 50L0 16L28 0L56 16L56 50L28 66L28 100" fill="none" stroke="#FCFCFC" stroke-width="2"></path>
<path d="M28 0L28 34L0 50L0 84L28 100L56 84L56 50L28 34" fill="none" stroke="#FBFBFB" stroke-width="2"></path>
</svg>

After

Width:  |  Height:  |  Size: 347 B

View File

@ -10,27 +10,22 @@ import ResetPasswordForm from "./lib/reset-password/reset-password-form";
import jslogger = require("js-logger"); import jslogger = require("js-logger");
import jQuery = require("jquery"); import jQuery = require("jquery");
import U2fApi = require("u2f-api"); import U2fApi = require("u2f-api");
import Endpoints = require("../../shared/api");
jslogger.useDefaults(); jslogger.useDefaults();
jslogger.setLevel(jslogger.INFO); jslogger.setLevel(jslogger.INFO);
export = { (function () {
firstfactor: function () { if (window.location.pathname == Endpoints.FIRST_FACTOR_GET)
FirstFactor(window, jQuery, FirstFactorValidator, jslogger); FirstFactor(window, jQuery, FirstFactorValidator, jslogger);
}, else if (window.location.pathname == Endpoints.SECOND_FACTOR_GET)
secondfactor: function () { SecondFactor(window, jQuery, U2fApi);
SecondFactor(window, jQuery, U2fApi); else if (window.location.pathname == Endpoints.SECOND_FACTOR_TOTP_IDENTITY_FINISH_GET)
}, TOTPRegister(window, jQuery);
register_totp: function() { else if (window.location.pathname == Endpoints.SECOND_FACTOR_U2F_IDENTITY_FINISH_GET)
TOTPRegister(window, jQuery); U2fRegister(window, jQuery);
}, else if (window.location.pathname == Endpoints.RESET_PASSWORD_IDENTITY_FINISH_GET)
register_u2f: function () { ResetPasswordForm(window, jQuery);
U2fRegister(window, jQuery); else if (window.location.pathname == Endpoints.RESET_PASSWORD_REQUEST_GET)
}, ResetPasswordRequest(window, jQuery);
reset_password_request: function () { })();
ResetPasswordRequest(window, jQuery);
},
reset_password_form: function () {
ResetPasswordForm(window, jQuery);
}
};

View File

@ -74,7 +74,7 @@ ldap:
authentication_methods: authentication_methods:
default_method: two_factor default_method: two_factor
per_subdomain_methods: per_subdomain_methods:
basicauth.test.local: single_factor single_factor.test.local: single_factor
# Access Control # Access Control
# #

View File

@ -1,222 +0,0 @@
###############################################################
# Authelia configuration #
###############################################################
# The port to listen on
port: 80
# Log level
#
# Level of verbosity for logs
logs_level: debug
# LDAP configuration
#
# Example: for user john, the DN will be cn=john,ou=users,dc=example,dc=com
ldap:
# The url of the ldap server
url: ldap://openldap
# The base dn for every entries
base_dn: dc=example,dc=com
# An additional dn to define the scope to all users
additional_users_dn: ou=users
# The users filter used to find the user DN
# {0} is a matcher replaced by username.
# 'cn={0}' by default.
users_filter: cn={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.
# {0} is a matcher replaced by username.
# {dn} is a matcher replaced by user DN.
# 'member={dn}' by default.
groups_filter: (&(member={dn})(objectclass=groupOfNames))
# 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: cn=admin,dc=example,dc=com
password: password
# Authentication methods
#
# Authentication methods can be defined per subdomain.
# There are currently two available methods: "single_factor" and "two_factor"
#
# Note: by default a domain uses "two_factor" method.
#
# Note: 'per_subdomain_methods' is a dictionary where keys must be subdomains and
# values must be one of the two possible methods.
#
# Note: 'per_subdomain_methods' is optional.
authentication_methods:
default_method: two_factor
per_subdomain_methods:
basicauth.test.local: single_factor
# Access Control
#
# Access control is a set of rules you can use to restrict user access to certain
# resources.
# Any (apply to anyone), per-user or per-group rules can be defined.
#
# If 'access_control' is not defined, ACL rules are disabled and the `allow` default
# policy 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 the pattern in simple quotes when using the wildcard for the YAML
# to be syntaxically correct.
#
# Definition: A `rule` is an object with the following keys: `domain`, `policy`
# and `resources`.
# - `domain` defines which domain or set of domains the rule applies to.
# - `policy` is the policy to apply to resources. It must be either `allow` or `deny`.
# - `resources` is a list of regular expressions that matches a set of resources to
# apply the policy to.
#
# Note: Rules follow an order of priority defined as follows:
# In each category (`any`, `groups`, `users`), the latest rules have the highest
# priority. In other words, it means that if a given resource matches two rules in the
# same category, the latest one overrides the first one.
# Each category has also its own priority. That is, `users` has the highest priority, then
# `groups` and `any` has the lowest priority. It means if two rules in different categories
# match a given resource, the one in the category with the highest priority overrides the
# other one.
#
access_control:
# Default policy can either be `allow` or `deny`.
# It is the policy applied to any resource if it has not been overriden
# in the `any`, `groups` or `users` category.
default_policy: deny
# The rules that apply to anyone.
# The value is a list of rules.
any:
- domain: public.test.local
policy: allow
# Group-based rules. The key is a group name and the value
# is a list of rules.
groups:
admin:
# All resources in all domains
- domain: '*.test.local'
policy: allow
# Except mx2.mail.test.local (it restricts the first rule)
- domain: 'mx2.mail.test.local'
policy: deny
dev:
- domain: dev.test.local
policy: allow
resources:
- '^/groups/dev/.*$'
# User-based rules. The key is a user name and the value
# is a list of rules.
users:
john:
- domain: dev.test.local
policy: allow
resources:
- '^/users/john/.*$'
harry:
- domain: dev.test.local
policy: allow
resources:
- '^/users/harry/.*$'
bob:
- domain: '*.mail.test.local'
policy: allow
- domain: 'dev.test.local'
policy: allow
resources:
- '^/users/bob/.*$'
# Configuration of session cookies
#
# The session cookies identify the user once logged in.
session:
# The secret to encrypt the session cookie.
secret: unsecure_session_secret
# 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: 300000 # 5 minutes
# 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: test.local
# The redis connection details
redis:
host: redis
port: 6379
# 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 for disabling regulation.
max_retries: 3
# The length of time between login attempts before user is banned.
find_time: 15
# The length of time before a banned user can login again.
ban_time: 4
# 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: /var/lib/authelia/store
# Settings to connect to mongo server
mongo:
url: mongodb://mongo/authelia
# 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 gmail account to send the notifications. You can use an app password.
# gmail:
# username: user@example.com
# password: yourpassword
# sender: admin@example.com
# Use a SMTP server for sending notifications
smtp:
username: test
password: password
secure: false
host: 'smtp'
port: 1025
sender: admin@example.com

View File

@ -52,7 +52,7 @@
mx2.main.test.local <a href="https://mx2.mail.test.local:8080/secret.html"> / secret.html</a> mx2.main.test.local <a href="https://mx2.mail.test.local:8080/secret.html"> / secret.html</a>
</li> </li>
<li> <li>
basicauth.test.local <a href="https://basicauth.test.local:8080/secret.html"> / secret.html</a> single_factor.test.local <a href="https://single_factor.test.local:8080/secret.html"> / secret.html</a>
</li> </li>
</ul> </ul>

View File

@ -244,9 +244,9 @@ http {
server { server {
listen 443 ssl; listen 443 ssl;
root /usr/share/nginx/html/basicauth.test.local; root /usr/share/nginx/html/single_factor.test.local;
server_name basicauth.test.local; server_name single_factor.test.local;
ssl on; ssl on;
ssl_certificate /etc/ssl/server.crt; ssl_certificate /etc/ssl/server.crt;

View File

@ -16,6 +16,3 @@ block content
a(href=reset_password_request_endpoint, class="pull-right link forgot-password") Forgot password? a(href=reset_password_request_endpoint, class="pull-right link forgot-password") Forgot password?
<span class="clearfix"></span> <span class="clearfix"></span>
</form> </form>
block entrypoint
<script>authelia.firstfactor();</script>

View File

@ -1,30 +1,32 @@
block variables block variables
html html
head head
title Authelia - 2FA title Authelia - 2FA
meta(name="viewport", content="width=device-width, initial-scale=1.0")/ meta(name="viewport", content="width=device-width, initial-scale=1.0")/
link(rel="icon", href="/img/icon.png" type="image/png" sizes="32x32")/ meta(name="robots", content="noindex, nofollow, nosnippet, noarchive")/
link(rel="stylesheet", type="text/css", href="/css/authelia.css")/ meta(http-equiv="Content-Security-Policy", content="default-src 'self'; img-src 'self' data:;")/
if redirection_url link(rel="icon", href="/img/icon.png" type="image/png" sizes="32x32")/
<meta http-equiv="refresh" content="4;url=#{redirection_url}"> link(rel="stylesheet", type="text/css", href="/css/authelia.css")/
body if redirection_url
<div class="container"> <meta http-equiv="refresh" content="4;url=#{redirection_url}">
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 #{page_classname}">
block form-header
<div class="row"> <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="form col-xs-10 col-xs-offset-1 col-sm-8 col-sm-offset-2 col-md-8 col-md-offset-2">
<div class="account-wall #{page_classname}"> block content
block form-header </div>
<div class="row">
<div class="form col-xs-10 col-xs-offset-1 col-sm-8 col-sm-offset-2 col-md-8 col-md-offset-2">
block content
</div>
</div>
<div class="row 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>
<div class="row 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>
script(src="/js/authelia.js") </div>
block entrypoint </div>
block entrypoint
script(src="/js/authelia.js")

View File

@ -18,6 +18,3 @@ block content
<button id="reset-password-button" class="btn btn-lg btn-primary btn-block" type="submit">Reset Password</button> <button id="reset-password-button" class="btn btn-lg btn-primary btn-block" type="submit">Reset Password</button>
<span class="clearfix"></span> <span class="clearfix"></span>
</form> </form>
block entrypoint
<script>authelia.reset_password_form();</script>

View File

@ -17,7 +17,3 @@ block content
<button id="reset-password-button" class="btn btn-lg btn-primary btn-block" type="submit">Reset Password</button> <button id="reset-password-button" class="btn btn-lg btn-primary btn-block" type="submit">Reset Password</button>
<span class="clearfix"></span> <span class="clearfix"></span>
</form> </form>
block entrypoint
<script>authelia.reset_password_request();</script>

View File

@ -5,25 +5,20 @@ block form-header
<img class="header-img" src="../img/padlock.png" alt=""> <img class="header-img" src="../img/padlock.png" alt="">
block content block content
p Hi <b>#{username}</b>, please complete second factor or <a href="/logout">logout</a>. p Hi <b>#{username}</b>, please complete second factor or <a href="/logout">logout</a>.
<div class="notification notification-totp"></div> <div class="notification notification-totp"></div>
<form class="form-signin totp"> <form class="form-signin totp">
<div class="form-inputs"> <div class="form-inputs">
<input type="text" autocomplete="off" class="form-control" id="token" placeholder="Token" required autofocus> <input type="text" autocomplete="off" class="form-control" id="token" placeholder="Token" required autofocus>
</div> </div>
<button class="btn btn-lg btn-primary btn-block totp-button" type="submit">TOTP</button> <button class="btn btn-lg btn-primary btn-block totp-button" type="submit">TOTP</button>
a(href=totp_identity_start_endpoint, class="pull-right link register-totp") Need to register? a(href=totp_identity_start_endpoint, class="pull-right link register-totp") Need to register?
<span class="clearfix"></span> <span class="clearfix"></span>
</form> </form>
<hr> <hr>
<div class="notification notification-u2f"></div> <div class="notification notification-u2f"></div>
<form class="form-signin u2f"> <form class="form-signin u2f">
<button class="btn btn-lg btn-primary btn-block u2f-button" type="submit">U2F</button> <button class="btn btn-lg btn-primary btn-block u2f-button" type="submit">U2F</button>
a(href=u2f_identity_start_endpoint, class="pull-right link register-u2f") Need to register? a(href=u2f_identity_start_endpoint, class="pull-right link register-u2f") Need to register?
<span class="clearfix"></span> <span class="clearfix"></span>
</form> </form>
block entrypoint
<script>
| authelia.secondfactor();
</script>

View File

@ -14,6 +14,3 @@ block content
block entrypoint block entrypoint
<script src="/js/qrcode.min.js"></script> <script src="/js/qrcode.min.js"></script>
<script>
| authelia.register_totp();
</script>

View File

@ -9,6 +9,3 @@ block form-header
block content block content
<img src="/img/pendrive.png" alt="pendrive" /> <img src="/img/pendrive.png" alt="pendrive" />
block entrypoint
<script>window.authelia.register_u2f()</script>

View File

@ -17,7 +17,7 @@ Feature: User has access restricted access to domains
| https://dev.test.local:8080/users/bob/secret.html | | https://dev.test.local:8080/users/bob/secret.html |
| https://admin.test.local:8080/secret.html | | https://admin.test.local:8080/secret.html |
| https://mx1.mail.test.local:8080/secret.html | | https://mx1.mail.test.local:8080/secret.html |
| https://basicauth.test.local:8080/secret.html | | https://single_factor.test.local:8080/secret.html |
And I have no access to: And I have no access to:
| url | | url |
| https://mx2.mail.test.local:8080/secret.html | | https://mx2.mail.test.local:8080/secret.html |
@ -42,7 +42,7 @@ Feature: User has access restricted access to domains
| https://admin.test.local:8080/secret.html | | https://admin.test.local:8080/secret.html |
| https://dev.test.local:8080/users/john/secret.html | | https://dev.test.local:8080/users/john/secret.html |
| https://dev.test.local:8080/users/harry/secret.html | | https://dev.test.local:8080/users/harry/secret.html |
| https://basicauth.test.local:8080/secret.html | | https://single_factor.test.local:8080/secret.html |
@need-registered-user-harry @need-registered-user-harry
Scenario: User harry has restricted access Scenario: User harry has restricted access
@ -64,4 +64,4 @@ Feature: User has access restricted access to domains
| https://dev.test.local:8080/users/john/secret.html | | https://dev.test.local:8080/users/john/secret.html |
| https://mx1.mail.test.local:8080/secret.html | | https://mx1.mail.test.local:8080/secret.html |
| https://mx2.mail.test.local:8080/secret.html | | https://mx2.mail.test.local:8080/secret.html |
| https://basicauth.test.local:8080/secret.html | | https://single_factor.test.local:8080/secret.html |

View File

@ -2,10 +2,10 @@ Feature: User is redirected when factors are already validated
@need-registered-user-john @need-registered-user-john
Scenario: User has validated first factor and tries to access service protected by second factor. He is then redirect to second factor step. Scenario: User has validated first factor and tries to access service protected by second factor. He is then redirect to second factor step.
When I visit "https://basicauth.test.local:8080/secret.html" When I visit "https://single_factor.test.local:8080/secret.html"
And I'm redirected to "https://auth.test.local:8080/?redirect=https%3A%2F%2Fbasicauth.test.local%3A8080%2Fsecret.html" And I'm redirected to "https://auth.test.local:8080/?redirect=https%3A%2F%2Fsingle_factor.test.local%3A8080%2Fsecret.html"
And I login with user "john" and password "password" And I login with user "john" and password "password"
And I'm redirected to "https://basicauth.test.local:8080/secret.html" And I'm redirected to "https://single_factor.test.local:8080/secret.html"
And I visit "https://public.test.local:8080/secret.html" And I visit "https://public.test.local:8080/secret.html"
Then I'm redirected to "https://auth.test.local:8080/secondfactor?redirect=https%3A%2F%2Fpublic.test.local%3A8080%2Fsecret.html" Then I'm redirected to "https://auth.test.local:8080/secondfactor?redirect=https%3A%2F%2Fpublic.test.local%3A8080%2Fsecret.html"

View File

@ -2,9 +2,9 @@ Feature: User can access certain subdomains with single factor
@need-registered-user-john @need-registered-user-john
Scenario: User is redirected to service after first factor if allowed Scenario: User is redirected to service after first factor if allowed
When I visit "https://auth.test.local:8080/?redirect=https%3A%2F%2Fbasicauth.test.local%3A8080%2Fsecret.html" When I visit "https://auth.test.local:8080/?redirect=https%3A%2F%2Fsingle_factor.test.local%3A8080%2Fsecret.html"
And I login with user "john" and password "password" And I login with user "john" and password "password"
Then I'm redirected to "https://basicauth.test.local:8080/secret.html" Then I'm redirected to "https://single_factor.test.local:8080/secret.html"
@need-registered-user-john @need-registered-user-john
Scenario: Redirection after first factor fails if single_factor not allowed. It redirects user to first factor. Scenario: Redirection after first factor fails if single_factor not allowed. It redirects user to first factor.