Commit adf55b09 authored by Luc Didry's avatar Luc Didry

Add Ldap and Htpasswd authentication (fix #8)

This commit is dedicated to Schoumi, who is supporting me on Tipeee.
Many thanks :-)
parent 847c035c
Pipeline #10545 failed with stage
in 4 minutes and 45 seconds
......@@ -3,6 +3,7 @@ Revision history for Perl application Lstu
0.08 ?
- Add Piwik tracking option
- Add Minion option for async counters increasing
- Add LDAP and Htpasswd authentication (#8)
0.07 Tue Dec 20 17:55:00 2016 +0100
- Add logo
......
......@@ -5,9 +5,12 @@ requires 'Net::Domain::TLD', '>= 1.74';
requires 'Mojolicious::Plugin::I18N';
requires 'Mojolicious::Plugin::DebugDumperHelper';
requires 'Mojolicious::Plugin::Piwik';
requires 'Mojolicious::Plugin::Authentication';
requires 'Minion';
requires 'Minion::Backend::SQLite';
requires 'Locale::Maketext';
requires 'Locale::Maketext::Extract';
requires 'Net::Abuse::Utils::Spamhaus';
requires 'IO::Socket::SSL';
requires 'Net::LDAP';
requires 'Apache::Htpasswd';
This diff is collapsed.
......@@ -6,6 +6,8 @@ use Data::Validate::URI qw(is_http_uri is_https_uri);
use Mojo::JSON qw(to_json decode_json);
use Mojo::URL;
use Net::Abuse::Utils::Spamhaus qw(check_fqdn);
use Net::LDAP;
use Apache::Htpasswd;
$ENV{MOJO_REVERSE_PROXY} = 1;
......@@ -15,17 +17,18 @@ sub startup {
my $config = $self->plugin('Config' => {
default => {
provisioning => 100,
provis_step => 5,
length => 8,
secret => ['hfudsifdsih'],
page_offset => 10,
theme => 'default',
ban_min_strike => 3,
minion => {
provisioning => 100,
provis_step => 5,
length => 8,
secret => ['hfudsifdsih'],
page_offset => 10,
theme => 'default',
ban_min_strike => 3,
minion => {
enabled => 0,
db_path => 'minion.db'
}
},
session_duration => 3600,
}
});
......@@ -55,6 +58,71 @@ sub startup {
# Piwik
$self->plugin('Piwik');
# Authentication (if configured)
if (defined($self->config('ldap')) || defined($self->config('htpasswd'))) {
die 'Unable to read '.$self->config('htpasswd') if (defined($self->config('htpasswd')) && !-r $self->config('htpasswd'));
$self->plugin('Authentication' =>
{
autoload_user => 1,
session_key => 'Lstu',
load_user => sub {
my ($c, $username) = @_;
return $username;
},
validate_user => sub {
my ($c, $username, $password, $extradata) = @_;
if (defined($c->config('ldap'))) {
my $ldap = Net::LDAP->new($c->config->{ldap}->{uri});
my $mesg = $ldap->bind($c->config->{ldap}->{bind_user}.$c->config->{ldap}->{bind_dn},
password => $c->config->{ldap}->{bind_pwd}
);
$mesg->code && die $mesg->error;
$mesg = $ldap->search(
base => $c->config->{ldap}->{user_tree},
filter => "(&(uid=$username)".$c->config->{ldap}->{user_filter}.")"
);
if ($mesg->code) {
$c->app->log->error($mesg->error);
return undef;
}
# Now we know that the user exists
$mesg = $ldap->bind('uid='.$username.$c->config->{ldap}->{bind_dn},
password => $password
);
if ($mesg->code) {
$c->app->log->info("[LDAP authentication failed] login: $username, IP: ".$c->ip);
$c->app->log->error("[LDAP authentication failed] ".$mesg->error);
return undef;
}
$c->app->log->info("[LDAP authentication successful] login: $username, IP: ".$c->ip);
} elsif (defined($c->config('htpasswd'))) {
my $htpasswd = new Apache::Htpasswd(
{
passwdFile => $c->config('htpasswd'),
ReadOnly => 1
}
);
if (!$htpasswd->htCheckPassword($username, $password)) {
return undef;
}
$c->app->log->info("[Simple authentication successful] login: $username, IP: ".$c->ip);
}
return $username;
}
}
);
$self->app->sessions->default_expiration($self->config('session_duration'));
}
# Minion
if ($config->{minion}->{enabled} && $config->{minion}->{db_path}) {
$self->plugin('Minion' => { SQLite => 'sqlite:'.$config->{minion}->{db_path} });
......@@ -256,9 +324,47 @@ sub startup {
# Normal route to controller
$r->get('/' => sub {
shift->render(template => 'index');
my $c = shift;
if ((!defined($c->config('ldap')) && !defined($c->config('htpasswd'))) || $c->is_user_authenticated) {
$c->render(template => 'index');
} else {
$c->redirect_to('login');
}
})->name('index');
if (defined $self->config('ldap') || defined $self->config('htpasswd')) {
# Login page
$r->get('/login' => sub {
my $c = shift;
if ($c->is_user_authenticated) {
$c->redirect_to('index');
} else {
$c->render(template => 'login');
}
});
# Authentication
$r->post('/login' => sub {
my $c = shift;
my $login = $c->param('login');
my $pwd = $c->param('password');
if($c->authenticate($login, $pwd)) {
$c->redirect_to('index');
} else {
$c->stash(msg => $c->l('Please, check your credentials: unable to authenticate.'));
$c->render(template => 'login');
}
});
# Logout page
$r->get('/logout' => sub {
my $c = shift;
if ($c->is_user_authenticated) {
$c->logout;
}
$c->render(template => 'logout');
})->name('logout');
}
$r->get('/api' => sub {
shift->render(template => 'api');
})->name('api');
......
This diff is collapsed.
......@@ -95,4 +95,27 @@
# enabled => 0,
# db_path => 'minion.db' # you can define it relative to lstu directory or set an absolute path
#},
# set `ldap` if you want that only authenticated users can shorten URLs
# please note that everybody can still use shortend URLs
# optional, no default
#ldap => {
# uri => 'ldaps://ldap.example.org',
# user_tree => 'ou=users,dc=example,dc=org',
# bind_dn => ',ou=users,dc=example,dc=org',
# bind_user => 'uid=ldap_user',
# bind_pwd => 'secr3t',
# user_filter => '!(uid=ldap_user)'
#},
# set `htpasswd` if you want to use an htpasswd file instead of ldap
# create the file with `htpasswd -c lstu.passwd user`, update it with `htpasswd lstu.passwd user2`
# make sure that lstu can read the file!
# optional, no default
#htpasswd => 'lstu.passwd',
# if you've set ldap or htpasswd above, the session will last `session_duration` seconds before
# the user needs to reauthenticate
# optional, default is 3600
#session_duration => 3600,
};
luc:$apr1$zG4UAKGa$FqSi4widrkVH/pT3qPawd.
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
use Mojo::Base -strict;
use Mojo::JSON qw(true false);
use Mojo::Util qw(slurp spurt);
use Test::More;
use Test::Mojo;
......@@ -115,4 +116,43 @@ $t->post_ok('/a' => form => { lsturl => ' https://fiat-tux.fr', format => 'json'
->json_is('/success' => true, '/url' => 'https://fiat-tux.fr')
->json_like('/short' => qr#http://127\.0\.0\.1:\d+/[-_a-zA-Z0-9]{8}#);
# Test htpasswd
my $config = slurp 'lstu.conf';
my $config_orig = $config;
$config =~ s/#?htpasswd.*/htpasswd => 't\/lstu.passwd'/gm;
spurt $config, 'lstu.conf';
LstuModel::Ban->delete_where('1 = 1'); # Reset banishing
LstuModel::Lstu->delete_where('1 = 1');
$t = Test::Mojo->new('Lstu');
$t->get_ok('/')
->status_is(302);
$t->get_ok('/login')
->status_is(200)
->content_like(qr/Login/);
$t->post_ok('/login' => form => { login => 'luc', password => 'titi' })
->status_is(200)
->content_like(qr/Please, check your credentials: unable to authenticate\./);
$t->post_ok('/a' => form => { lsturl => 'https://lstu.fr', format => 'json' })
->status_is(302);
$t->post_ok('/login' => form => { login => 'luc', password => 'toto' })
->status_is(302);
$t->post_ok('/a' => form => { lsturl => 'https://lstu.fr', format => 'json' })
->status_is(200)
->json_has('url', 'short', 'success')
->json_is('/success' => true, '/url' => 'https://lstu.fr')
->json_like('/short' => qr#http://127\.0\.0\.1:\d+/[-_a-zA-Z0-9]{8}#);
$t->get_ok('/logout')
->status_is(200)
->content_like(qr/You have been successfully logged out\./);
spurt $config_orig, 'lstu.conf';
done_testing();
......@@ -20,7 +20,7 @@ msgstr ""
"X-Poedit-SourceCharset: UTF-8\n"
#. ($url)
#: lib/Lstu/Controller/Lstu.pm:106
#: lib/Lstu/Controller/Lstu.pm:108
msgid "%1 is not a valid URL."
msgstr ""
......@@ -32,7 +32,7 @@ msgstr ""
msgid "Admin password"
msgstr ""
#: lib/Lstu/Controller/Admin.pm:57 lib/Lstu/Controller/Admin.pm:90
#: lib/Lstu/Controller/Admin.pm:61 lib/Lstu/Controller/Admin.pm:94
msgid "Bad password"
msgstr ""
......@@ -92,6 +92,10 @@ msgstr ""
msgid "License:"
msgstr ""
#: themes/default/templates/layouts/default.html.ep:62
msgid "Logout"
msgstr ""
#: themes/default/templates/stats.html.ep:10
msgid "Logout from admin stats"
msgstr ""
......@@ -101,7 +105,7 @@ msgid "Next"
msgstr ""
#. ($c->config('contact')
#: lib/Lstu/Controller/Lstu.pm:98
#: lib/Lstu/Controller/Lstu.pm:100
msgid "No shortened URL available. Please retry or contact the administrator at %1. Your URL to shorten: %2"
msgstr ""
......@@ -109,6 +113,10 @@ msgstr ""
msgid "Parameters:"
msgstr ""
#: lib/Lstu.pm:353
msgid "Please, check your credentials: unable to authenticate."
msgstr ""
#: themes/default/templates/stats.html.ep:63
msgid "Previous"
msgstr ""
......@@ -125,36 +133,40 @@ msgstr ""
msgid "Shortened URL"
msgstr ""
#: themes/default/templates/layouts/default.html.ep:59 themes/default/templates/stats.html.ep:4
#: themes/default/templates/layouts/default.html.ep:64
msgid "Signin"
msgstr ""
#: themes/default/templates/layouts/default.html.ep:61 themes/default/templates/layouts/default.html.ep:67 themes/default/templates/stats.html.ep:4
msgid "Statistics"
msgstr ""
#. ($url->host)
#: lib/Lstu.pm:127
#: lib/Lstu.pm:226
msgid "The URL host or one of its redirection(s) (%1) is blacklisted at Spamhaus. I refuse to shorten it."
msgstr ""
#. ($url->host)
#: lib/Lstu.pm:140
#: lib/Lstu.pm:239
msgid "The URL redirects 3 times or most. It's most likely a dangerous URL (spam, phishing, etc.). I refuse to shorten it."
msgstr ""
#. ($c->url_for('/')
#: lib/Lstu/Controller/Admin.pm:79 lib/Lstu/Controller/Lstu.pm:221
#: lib/Lstu/Controller/Admin.pm:83 lib/Lstu/Controller/Lstu.pm:275
msgid "The shortened URL %1 doesn't exist."
msgstr ""
#. ($custom_url)
#: lib/Lstu/Controller/Lstu.pm:50
#: lib/Lstu/Controller/Lstu.pm:52
msgid "The shortened text (%1) is already used. Please choose another one."
msgstr ""
#. ($url)
#: lib/Lstu/Controller/Lstu.pm:48
#: lib/Lstu/Controller/Lstu.pm:50
msgid "The shortened text can contain only numbers, letters and the - and _ character, can't be \"a\", \"api\", \"d\" or \"stats\" or end with \".json\". Your URL to shorten: %1"
msgstr ""
#: lib/Lstu/Controller/Admin.pm:25
#: lib/Lstu/Controller/Admin.pm:26
msgid "Too many bad passwords. You're banned."
msgstr ""
......
......@@ -23,7 +23,7 @@ msgstr ""
"X-Poedit-SourceCharset: UTF-8\n"
#. ($url)
#: lib/Lstu/Controller/Lstu.pm:106
#: lib/Lstu/Controller/Lstu.pm:108
msgid "%1 is not a valid URL."
msgstr "%1 n’est pas une URL valide."
......@@ -35,7 +35,7 @@ msgstr "À propos"
msgid "Admin password"
msgstr "Mot de passe administrateur"
#: lib/Lstu/Controller/Admin.pm:57 lib/Lstu/Controller/Admin.pm:90
#: lib/Lstu/Controller/Admin.pm:61 lib/Lstu/Controller/Admin.pm:94
msgid "Bad password"
msgstr "Mot de passe incorrect"
......@@ -95,6 +95,10 @@ msgstr "JSON : succès"
msgid "License:"
msgstr "Licence :"
#: themes/default/templates/layouts/default.html.ep:62
msgid "Logout"
msgstr "Déconnexion"
#: themes/default/templates/stats.html.ep:10
msgid "Logout from admin stats"
msgstr "Déconnexion des stats admin"
......@@ -104,7 +108,7 @@ msgid "Next"
msgstr "Suivant"
#. ($c->config('contact')
#: lib/Lstu/Controller/Lstu.pm:98
#: lib/Lstu/Controller/Lstu.pm:100
msgid "No shortened URL available. Please retry or contact the administrator at %1. Your URL to shorten: %2"
msgstr "Il n’y a plus d’URL raccourcie disponible. Veuillez réessayer ou contactez l’administrateur sur %1. Rappel de l’URL à raccourcir : %2"
......@@ -112,6 +116,10 @@ msgstr "Il n’y a plus d’URL raccourcie disponible. Veuillez réessayer ou co
msgid "Parameters:"
msgstr "Paramètres :"
#: lib/Lstu.pm:353
msgid "Please, check your credentials: unable to authenticate."
msgstr "Impossible de s’authentifier, veuillez vérifier vos identifiants"
#: themes/default/templates/stats.html.ep:63
msgid "Previous"
msgstr "Précédent"
......@@ -128,36 +136,40 @@ msgstr "Réponse :"
msgid "Shortened URL"
msgstr "URL raccourcie"
#: themes/default/templates/layouts/default.html.ep:59 themes/default/templates/stats.html.ep:4
#: themes/default/templates/layouts/default.html.ep:64
msgid "Signin"
msgstr "Connexion"
#: themes/default/templates/layouts/default.html.ep:61 themes/default/templates/layouts/default.html.ep:67 themes/default/templates/stats.html.ep:4
msgid "Statistics"
msgstr "Statistiques"
#. ($url->host)
#: lib/Lstu.pm:127
#: lib/Lstu.pm:226
msgid "The URL host or one of its redirection(s) (%1) is blacklisted at Spamhaus. I refuse to shorten it."
msgstr "L'hôte de l'URL ou d'une de ses redirections (%1) est considéré comme nocif par Spamhaus. Je refuse de la raccourcir."
#. ($url->host)
#: lib/Lstu.pm:140
#: lib/Lstu.pm:239
msgid "The URL redirects 3 times or most. It's most likely a dangerous URL (spam, phishing, etc.). I refuse to shorten it."
msgstr "L'URL redirige 3 fois ou plus vers un autre site. Il est probable qu'il s'agisse d'une URL dangereuse (pourriel, hameçonnage, etc.). Je refuse de la raccourcir."
#. ($c->url_for('/')
#: lib/Lstu/Controller/Admin.pm:79 lib/Lstu/Controller/Lstu.pm:221
#: lib/Lstu/Controller/Admin.pm:83 lib/Lstu/Controller/Lstu.pm:275
msgid "The shortened URL %1 doesn't exist."
msgstr "L’URL raccourcie %1 n’existe pas"
#. ($custom_url)
#: lib/Lstu/Controller/Lstu.pm:50
#: lib/Lstu/Controller/Lstu.pm:52
msgid "The shortened text (%1) is already used. Please choose another one."
msgstr "Le texte du raccourci (%1) est déjà utilisé. Veuillez en choisir un autre"
#. ($url)
#: lib/Lstu/Controller/Lstu.pm:48
#: lib/Lstu/Controller/Lstu.pm:50
msgid "The shortened text can contain only numbers, letters and the - and _ character, can't be \"a\", \"api\", \"d\" or \"stats\" or end with \".json\". Your URL to shorten: %1"
msgstr "Le texte du raccourci ne doit contenir que des chiffres, des lettres et les caractères - et _, ne peut être \"a\", \"api\", \"d\" ou \"stats\" ou se terminer par \".json\". Rappel de l’URL à raccourcir : %1"
#: lib/Lstu/Controller/Admin.pm:25
#: lib/Lstu/Controller/Admin.pm:26
msgid "Too many bad passwords. You're banned."
msgstr "Trop de mauvais mots de passe. Vous êtes banni."
......
......@@ -23,7 +23,7 @@ msgstr ""
"X-Poedit-SourceCharset: UTF-8\n"
#. ($url)
#: lib/Lstu/Controller/Lstu.pm:106
#: lib/Lstu/Controller/Lstu.pm:108
msgid "%1 is not a valid URL."
msgstr "%1 es pas una URL valida."
......@@ -35,7 +35,7 @@ msgstr "A prepaus"
msgid "Admin password"
msgstr "Senhal administrator"
#: lib/Lstu/Controller/Admin.pm:57 lib/Lstu/Controller/Admin.pm:90
#: lib/Lstu/Controller/Admin.pm:61 lib/Lstu/Controller/Admin.pm:94
msgid "Bad password"
msgstr "Senhal incorrèct"
......@@ -95,6 +95,10 @@ msgstr "JSON : succès"
msgid "License:"
msgstr "Licéncia :"
#: themes/default/templates/layouts/default.html.ep:62
msgid "Logout"
msgstr "Desconnexion"
#: themes/default/templates/stats.html.ep:10
msgid "Logout from admin stats"
msgstr "Desconnexion de las estatisticas admin"
......@@ -104,7 +108,7 @@ msgid "Next"
msgstr "Seguent"
#. ($c->config('contact')
#: lib/Lstu/Controller/Lstu.pm:98
#: lib/Lstu/Controller/Lstu.pm:100
msgid "No shortened URL available. Please retry or contact the administrator at %1. Your URL to shorten: %2"
msgstr "I a pas mai d’URL acorchadas disponiblas. Mercés de tornar ensejar o de contactar l’administrator sus %1. Recòrd de l’URL per acorchar : %2"
......@@ -112,6 +116,10 @@ msgstr "I a pas mai d’URL acorchadas disponiblas. Mercés de tornar ensejar o
msgid "Parameters:"
msgstr "Paramètres :"
#: lib/Lstu.pm:353
msgid "Please, check your credentials: unable to authenticate."
msgstr ""
#: themes/default/templates/stats.html.ep:63
msgid "Previous"
msgstr "Precedent"
......@@ -128,36 +136,40 @@ msgstr "Responsa :"
msgid "Shortened URL"
msgstr "URL acorchada"
#: themes/default/templates/layouts/default.html.ep:59 themes/default/templates/stats.html.ep:4
#: themes/default/templates/layouts/default.html.ep:64
msgid "Signin"
msgstr "Connexion"
#: themes/default/templates/layouts/default.html.ep:61 themes/default/templates/layouts/default.html.ep:67 themes/default/templates/stats.html.ep:4
msgid "Statistics"
msgstr "Estatisticas"
#. ($url->host)
#: lib/Lstu.pm:127
#: lib/Lstu.pm:226
msgid "The URL host or one of its redirection(s) (%1) is blacklisted at Spamhaus. I refuse to shorten it."
msgstr "L’òste de l’URL o d’una de sas redireccions (%1) es considerat coma nociu per Spamhaus. Refusi de l’acorchar."
#. ($url->host)
#: lib/Lstu.pm:140
#: lib/Lstu.pm:239
msgid "The URL redirects 3 times or most. It's most likely a dangerous URL (spam, phishing, etc.). I refuse to shorten it."
msgstr "L’URL endralha 3 còps o mai cap a un a autre site. Pòt èsser una URL dangerossa (porrièl, pesca electronica, etc). Refusi de l’acorchar"
#. ($c->url_for('/')
#: lib/Lstu/Controller/Admin.pm:79 lib/Lstu/Controller/Lstu.pm:221
#: lib/Lstu/Controller/Admin.pm:83 lib/Lstu/Controller/Lstu.pm:275
msgid "The shortened URL %1 doesn't exist."
msgstr "L’URL acorchada %1 existís pas"
#. ($custom_url)
#: lib/Lstu/Controller/Lstu.pm:50
#: lib/Lstu/Controller/Lstu.pm:52
msgid "The shortened text (%1) is already used. Please choose another one."
msgstr "Lo tèxte de l’acorchi (%1) es ja utilizat. Mercés de ne causir un autre"
#. ($url)
#: lib/Lstu/Controller/Lstu.pm:48
#: lib/Lstu/Controller/Lstu.pm:50
msgid "The shortened text can contain only numbers, letters and the - and _ character, can't be \"a\", \"api\", \"d\" or \"stats\" or end with \".json\". Your URL to shorten: %1"
msgstr "Lo tèxte de l’acorchi deu pas que contenir de chifras, letras e los caractèrs - e _, èsser \"a\", \"api\", \"d\" o \"stats\" o acabar per \".json\". Recòrd de l’URL per acorchar : %1"
#: lib/Lstu/Controller/Admin.pm:25
#: lib/Lstu/Controller/Admin.pm:26
msgid "Too many bad passwords. You're banned."
msgstr "Tròp de marrits senhals. Sètz bandit."
......
......@@ -52,11 +52,20 @@
</div>
<%= link_to url_for('/') => (class => 'link_nocol') => begin %><h1 class="hennypenny">Let's Shorten That Url</h1><% end %>
<p>
<small>&copy; 2013 — 2015 <%= link_to 'Luc Didry' => 'https://fiat-tux.fr' %> —
<%= l('License:') %> <%= link_to 'WTFPL' => 'http://www.wtfpl.net/' %> —
<small>&copy; 2013 — 2017 <%= link_to 'Luc Didry' => 'https://fiat-tux.fr' %> —
<%= l('License:') %> <%= link_to 'WTFPL' => 'http://www.wtfpl.net/' %> —
<%= link_to l('About') => 'https://framagit.org/luc/lstu#tab-readme' %> —
<%= link_to 'API' => url_for('api') %> —
<%= link_to 'API' => url_for('api') %> —
% if (defined(config('ldap')) || defined(config('htpasswd'))) {
% if (is_user_authenticated()) {
<%= link_to l('Statistics') => url_for('stats') %> —
<%= link_to l('Logout') => url_for('/logout')%>
% } else {
<%= link_to l('Signin') => url_for('/login') %>
% }
% } else {
<%= link_to l('Statistics') => url_for('stats') %>
% }
</small>
</p>
<%= content %>
......
% # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab:
% if (defined stash('msg')) {
<%= stash('msg') %>
% }
<form method="post" action="<%= url_for('login') %>" class="form-inline">
<div class="form-group">
<label for="login"><%= l('Login') %></label>
<input id="login" type="text" class="validate" name="login">
</div>
<div class="form-group">
<label for="password"><%= l('Password') %></label>
<input id="password" type="password" class="validate" name="password">
</div>
<button class="btn btn-default" type="submit" name="action">
<%= l('Signin') %>
</button>
</form>
% # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab:
<h4><%= l('You have been successfully logged out.') %></h4>
<p>
<a href="<%= url_for('login') %>" class="btn btn-default"><%= l('Signin') %></a>
</p
......@@ -35,11 +35,20 @@
</div>
<%= link_to url_for('/') => (class => 'link_nocol') => begin %><h1 class="hennypenny">Let's Shorten That Url</h1><% end %>
<p>
<small>&copy; 2013 — 2016 <%= link_to 'Luc Didry' => 'https://fiat-tux.fr' %> —
<%= l('License:') %> <%= link_to 'WTFPL' => 'http://www.wtfpl.net/' %> —
<small>&copy; 2013 — 2017 <%= link_to 'Luc Didry' => 'https://fiat-tux.fr' %> —
<%= l('License:') %> <%= link_to 'WTFPL' => 'http://www.wtfpl.net/' %> —
<%= link_to l('About') => 'https://framagit.org/luc/lstu#tab-readme' %> —
<%= link_to 'API' => url_for('api') %> —
% if (defined(config('ldap')) || defined(config('htpasswd'))) {
% if (is_user_authenticated()) {
<%= link_to l('Statistics') => url_for('stats') %> —
<%= link_to l('Logout') => url_for('/logout')%>
% } else {
<%= link_to l('Signin') => url_for('/login') %>
% }
% } else {
<%= link_to l('Statistics') => url_for('stats') %>
% }
</small>
</p>
<%= content %>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment