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:
- admin.test.local
- auth.test.local
- basicauth.test.local
- single_factor.test.local
- dev.test.local
- home.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
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 mx1.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
### 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
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
### Authelia configuration
The configuration of the server is defined in the file

View File

@ -1,6 +1,6 @@
body {
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NiIgaGVpZ2h0PSIxMDAiPgo8cmVjdCB3aWR0aD0iNTYiIGhlaWdodD0iMTAwIiBmaWxsPSIjRkZGRkZGIj48L3JlY3Q+CjxwYXRoIGQ9Ik0yOCA2NkwwIDUwTDAgMTZMMjggMEw1NiAxNkw1NiA1MEwyOCA2NkwyOCAxMDAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI0ZDRkNGQyIgc3Ryb2tlLXdpZHRoPSIyIj48L3BhdGg+CjxwYXRoIGQ9Ik0yOCAwTDI4IDM0TDAgNTBMMCA4NEwyOCAxMDBMNTYgODRMNTYgNTBMMjggMzQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI0ZCRkJGQiIgc3Ryb2tlLXdpZHRoPSIyIj48L3BhdGg+Cjwvc3ZnPg==");
background-image: url("/img/background.svg");
}
.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 jQuery = require("jquery");
import U2fApi = require("u2f-api");
import Endpoints = require("../../shared/api");
jslogger.useDefaults();
jslogger.setLevel(jslogger.INFO);
export = {
firstfactor: function () {
FirstFactor(window, jQuery, FirstFactorValidator, jslogger);
},
secondfactor: function () {
SecondFactor(window, jQuery, U2fApi);
},
register_totp: function() {
TOTPRegister(window, jQuery);
},
register_u2f: function () {
U2fRegister(window, jQuery);
},
reset_password_request: function () {
ResetPasswordRequest(window, jQuery);
},
reset_password_form: function () {
ResetPasswordForm(window, jQuery);
}
};
(function () {
if (window.location.pathname == Endpoints.FIRST_FACTOR_GET)
FirstFactor(window, jQuery, FirstFactorValidator, jslogger);
else if (window.location.pathname == Endpoints.SECOND_FACTOR_GET)
SecondFactor(window, jQuery, U2fApi);
else if (window.location.pathname == Endpoints.SECOND_FACTOR_TOTP_IDENTITY_FINISH_GET)
TOTPRegister(window, jQuery);
else if (window.location.pathname == Endpoints.SECOND_FACTOR_U2F_IDENTITY_FINISH_GET)
U2fRegister(window, jQuery);
else if (window.location.pathname == Endpoints.RESET_PASSWORD_IDENTITY_FINISH_GET)
ResetPasswordForm(window, jQuery);
else if (window.location.pathname == Endpoints.RESET_PASSWORD_REQUEST_GET)
ResetPasswordRequest(window, jQuery);
})();

View File

@ -74,7 +74,7 @@ ldap:
authentication_methods:
default_method: two_factor
per_subdomain_methods:
basicauth.test.local: single_factor
single_factor.test.local: single_factor
# Access Control
#
@ -231,4 +231,4 @@ notifier:
secure: false
host: 'smtp'
port: 1025
sender: admin@example.com
sender: admin@example.com

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>
</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>
</ul>

View File

@ -244,9 +244,9 @@ http {
server {
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_certificate /etc/ssl/server.crt;

View File

@ -15,7 +15,4 @@ block content
<!-- <label class="checkbox pull-left"><input type="checkbox" value="remember-me">Remember me</label> -->
a(href=reset_password_request_endpoint, class="pull-right link forgot-password") Forgot password?
<span class="clearfix"></span>
</form>
block entrypoint
<script>authelia.firstfactor();</script>
</form>

View File

@ -1,30 +1,32 @@
block variables
html
head
title Authelia - 2FA
meta(name="viewport", content="width=device-width, initial-scale=1.0")/
link(rel="icon", href="/img/icon.png" type="image/png" sizes="32x32")/
link(rel="stylesheet", type="text/css", href="/css/authelia.css")/
if redirection_url
<meta http-equiv="refresh" content="4;url=#{redirection_url}">
body
<div class="container">
head
title Authelia - 2FA
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")/
if redirection_url
<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="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="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 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>
script(src="/js/authelia.js")
block entrypoint
</div>
</div>
block entrypoint
script(src="/js/authelia.js")

View File

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

View File

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

View File

@ -5,25 +5,20 @@ block form-header
<img class="header-img" src="../img/padlock.png" alt="">
block content
p Hi <b>#{username}</b>, please complete second factor or <a href="/logout">logout</a>.
<div class="notification notification-totp"></div>
<form class="form-signin totp">
<div class="form-inputs">
<input type="text" autocomplete="off" class="form-control" id="token" placeholder="Token" required autofocus>
</div>
<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?
<span class="clearfix"></span>
</form>
<hr>
<div class="notification notification-u2f"></div>
<form class="form-signin u2f">
<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?
<span class="clearfix"></span>
</form>
block entrypoint
<script>
| authelia.secondfactor();
</script>
p Hi <b>#{username}</b>, please complete second factor or <a href="/logout">logout</a>.
<div class="notification notification-totp"></div>
<form class="form-signin totp">
<div class="form-inputs">
<input type="text" autocomplete="off" class="form-control" id="token" placeholder="Token" required autofocus>
</div>
<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?
<span class="clearfix"></span>
</form>
<hr>
<div class="notification notification-u2f"></div>
<form class="form-signin u2f">
<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?
<span class="clearfix"></span>
</form>

View File

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

View File

@ -8,7 +8,4 @@ block form-header
<p>Touch the token to register your U2F device.</p>
block content
<img src="/img/pendrive.png" alt="pendrive" />
block entrypoint
<script>window.authelia.register_u2f()</script>
<img src="/img/pendrive.png" alt="pendrive" />

View File

@ -17,7 +17,7 @@ Feature: User has access restricted access to domains
| https://dev.test.local:8080/users/bob/secret.html |
| https://admin.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:
| url |
| 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://dev.test.local:8080/users/john/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
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://mx1.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
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"
And I'm redirected to "https://auth.test.local:8080/?redirect=https%3A%2F%2Fbasicauth.test.local%3A8080%2Fsecret.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%2Fsingle_factor.test.local%3A8080%2Fsecret.html"
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"
Then I'm redirected to "https://auth.test.local:8080/secondfactor?redirect=https%3A%2F%2Fpublic.test.local%3A8080%2Fsecret.html"
@ -31,4 +31,4 @@ Feature: User is redirected when factors are already validated
And I click on "TOTP"
And I'm redirected to "https://public.test.local:8080/secret.html"
And I visit "https://auth.test.local:8080?redirect=https://public.test.local:8080/secret.html"
Then I'm redirected to "https://public.test.local:8080/secret.html"
Then I'm redirected to "https://public.test.local:8080/secret.html"

View File

@ -2,9 +2,9 @@ Feature: User can access certain subdomains with single factor
@need-registered-user-john
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"
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
Scenario: Redirection after first factor fails if single_factor not allowed. It redirects user to first factor.