diff --git a/lemonldap-ng-portal/MANIFEST b/lemonldap-ng-portal/MANIFEST
index 8cab80a93..a881b9095 100644
--- a/lemonldap-ng-portal/MANIFEST
+++ b/lemonldap-ng-portal/MANIFEST
@@ -41,12 +41,12 @@ lib/Lemonldap/NG/Portal/Auth/Null.pm
lib/Lemonldap/NG/Portal/Auth/Proxy.pm
lib/Lemonldap/NG/Portal/Auth/Remote.pm
lib/Lemonldap/NG/Portal/Auth/Slave.pm
+lib/Lemonldap/NG/Portal/Auth/SSL.pm
lib/Lemonldap/NG/Portal/AuthCAS.pm
lib/Lemonldap/NG/Portal/AuthGoogle.pm
lib/Lemonldap/NG/Portal/AuthMulti.pm
lib/Lemonldap/NG/Portal/AuthOpenID.pm
lib/Lemonldap/NG/Portal/AuthOpenIDConnect.pm
-lib/Lemonldap/NG/Portal/AuthProxy.pm
lib/Lemonldap/NG/Portal/AuthRadius.pm
lib/Lemonldap/NG/Portal/AuthSAML.pm
lib/Lemonldap/NG/Portal/AuthSSL.pm
@@ -84,13 +84,16 @@ lib/Lemonldap/NG/Portal/Menu.pm
lib/Lemonldap/NG/Portal/OpenID/Server.pm
lib/Lemonldap/NG/Portal/OpenID/SREG.pm
lib/Lemonldap/NG/Portal/Password/Base.pm
+lib/Lemonldap/NG/Portal/Password/DBI.pm
lib/Lemonldap/NG/Portal/Password/Demo.pm
+lib/Lemonldap/NG/Portal/Password/LDAP.pm
lib/Lemonldap/NG/Portal/PasswordDBAD.pm
lib/Lemonldap/NG/Portal/PasswordDBChoice.pm
lib/Lemonldap/NG/Portal/PasswordDBDBI.pm
lib/Lemonldap/NG/Portal/PasswordDBLDAP.pm
lib/Lemonldap/NG/Portal/PasswordDBNull.pm
lib/Lemonldap/NG/Portal/Plugins/CDA.pm
+lib/Lemonldap/NG/Portal/Plugins/ForceAuth.pm
lib/Lemonldap/NG/Portal/Plugins/Notifications.pm
lib/Lemonldap/NG/Portal/Register.pm
lib/Lemonldap/NG/Portal/RegisterDBAD.pm
@@ -331,19 +334,21 @@ site/templates/pastel/register.tpl
site/templates/pastel/standardform.tpl
site/templates/pastel/yubikeyform.tpl
t/01-AuthDemo.t
-t/02-AuthAD.t
-t/02-AuthLDAP.t
-t/03-AuthDBI.t
-t/04-AuthNull.t
-t/05-AuthApache.t
-t/06-AuthSlave.t
-t/07-AuthRemote.t
-t/08-AuthProxy.t
-t/09-AuthChoice.t
-t/10-Notifications-File.t
-t/11-Notifications-DBI.t
-t/20-XSS-protection.t
-t/30-IssuerGet.t
+t/02-Password-Demo.t
+t/03-XSS-protection.t
+t/04-Notification-File.t
+t/20-Auth-and-password-DBI.t
+t/21-Auth-and-password-LDAP.t
+t/22-Auth-and-password-AD.t
+t/23-AuthNull.t
+t/24-AuthApache.t
+t/25-AuthSlave.t
+t/26-AuthRemote.t
+t/27-AuthProxy.t
+t/28-AuthChoice.t
+t/29-AuthSSL.t
+t/40-Notifications-DBI.t
+t/50-IssuerGet.t
t/90-translations.t
t/99-pod.t
t/lmConf-1.js
diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SSL.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SSL.pm
new file mode 100644
index 000000000..fb89aa71d
--- /dev/null
+++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SSL.pm
@@ -0,0 +1,48 @@
+package Lemonldap::NG::Portal::Auth::SSL;
+
+use strict;
+use Mouse;
+use Lemonldap::NG::Portal::Main::Constants
+ qw(PE_OK PE_BADCERTIFICATE PE_CERTIFICATEREQUIRED);
+
+our $VERSION = '2.0.0';
+
+extends 'Lemonldap::NG::Portal::Auth::Base';
+
+# PROPERTIES
+
+has SSLField => ( is => 'rw' );
+
+# INITIALIZATION
+
+sub init {
+ my ($self) = @_;
+ $self->SSLField( $self->conf->{SSLVar} ||= 'SSL_CLIENT_S_DN_Email' );
+}
+
+# Read username in SSL environment variables, or return an error
+# @return Lemonldap::NG::Portal constant
+sub extractFormInfo {
+ my ( $self, $req ) = @_;
+ return PE_OK
+ if ( $req->user( $req->{ $self->SSLField } ) );
+ if ( $req->{SSL_CLIENT_S_DN} ) {
+ $self->p->userError(
+ "$self->SSLField was not found in user certificate");
+ return PE_BADCERTIFICATE;
+ }
+ else {
+ $self->p->userError('No certificate found');
+ return PE_CERTIFICATEREQUIRED;
+ }
+}
+
+sub authenticate {
+ PE_OK;
+}
+
+sub getDisplayType {
+ return "logo";
+}
+
+1;
diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/AuthProxy.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/AuthProxy.pm
deleted file mode 100644
index 5100dae56..000000000
--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/AuthProxy.pm
+++ /dev/null
@@ -1,145 +0,0 @@
-## @file
-# Proxy authentication module
-
-## @class
-# Proxy authentication module: It simply call another Lemonldap::NG portal by
-# SOAP using credentials
-package Lemonldap::NG::Portal::AuthProxy;
-
-use strict;
-use Lemonldap::NG::Portal::_Proxy;
-use Lemonldap::NG::Portal::_WebForm;
-use Lemonldap::NG::Portal::Simple;
-use base qw(Lemonldap::NG::Portal::_WebForm Lemonldap::NG::Portal::_Proxy);
-
-our $VERSION = '2.0.0';
-
-## @apmethod int authInit()
-# Call Lemonldap::NG::Portal::_Proxy::proxyInit();
-# @return Lemonldap::NG::Portal constant
-*authInit = *Lemonldap::NG::Portal::_Proxy::proxyInit;
-
-## @apmethod int authenticate()
-# Call Lemonldap::NG::Portal::_Proxy::proxyQuery()
-# @return Lemonldap::NG::Portal constant
-*authenticate = *Lemonldap::NG::Portal::_Proxy::proxyQuery;
-
-## @apmethod int setAuthSessionInfo()
-# Call Lemonldap::NG::Portal::_Proxy::setSessionInfo()
-# @return Lemonldap::NG::Portal constant
-*setAuthSessionInfo = *Lemonldap::NG::Portal::_Proxy::setSessionInfo;
-
-## @apmethod int authFinish()
-# Does nothing.
-# @return Lemonldap::NG::Portal constant
-sub authFinish {
- PE_OK;
-}
-
-## @apmethod int authLogout()
-# Does nothing
-# @return Lemonldap::NG::Portal constant
-sub authLogout {
- PE_OK;
-}
-
-## @apmethod boolean authForce()
-# Does nothing
-# @return result
-sub authForce {
- return 0;
-}
-
-## @method string getDisplayType
-# @return display type
-sub getDisplayType {
- return "standardform";
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-=encoding utf8
-
-Lemonldap::NG::Portal::AuthProxy - Authentication module for Lemonldap::NG
-that delegates authentication to a remote Lemonldap::NG portal.
-
-The difference with Remote authentication module is that the client will never
-be redirected to the main Lemonldap::NG portal. This configuration is usable if
-you want to expose your internal SSO to another network (DMZ).
-
-=head1 SYNOPSIS
-
- use Lemonldap::NG::Portal::SharedConf;
- my $portal = new Lemonldap::NG::Portal::SharedConf(
-
- # REQUIRED PARAMETERS
- authentication => 'Proxy',
- userDB => 'Proxy',
- soapAuthService => 'https://auth.internal.network/',
-
- # OTHER PARAMETERS
- # remoteCookieName (default: same name)
- remoteCookieName => 'lemonldap',
- # soapSessionService (default ${soapAuthService}index.pl/sessions)
- soapSessionService =>
- 'https://auth2.internal.network/index.pl/sessions',
- );
-
-=head1 DESCRIPTION
-
-Authentication module for Lemonldap::NG portal that forward credentials to a
-remote Lemonldap::NGportal using SOAP request. Note that the remote portal must
-accept SOAP requests ("Soap=>1").
-
-=head1 SEE ALSO
-
-L
-
-=head1 AUTHOR
-
-=over
-
-=item Clement Oudot, Eclem.oudot@gmail.comE
-
-=item Xavier Guimard, Ex.guimard@free.frE
-
-=back
-
-=head1 BUG REPORT
-
-Use OW2 system to report bug or ask for features:
-L
-
-=head1 DOWNLOAD
-
-Lemonldap::NG is available at
-L
-
-=head1 COPYRIGHT AND LICENSE
-
-=over
-
-=item Copyright (C) 2009-2010 by Xavier Guimard, Ex.guimard@free.frE
-
-=item Copyright (C) 2010-2012 by Clement Oudot, Eclem.oudot@gmail.comE
-
-=back
-
-This library is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see L.
-
-=cut
diff --git a/lemonldap-ng-portal/t/29-AuthSSL.t b/lemonldap-ng-portal/t/29-AuthSSL.t
new file mode 100644
index 000000000..373aafe84
--- /dev/null
+++ b/lemonldap-ng-portal/t/29-AuthSSL.t
@@ -0,0 +1,32 @@
+use Test::More;
+use strict;
+
+require 't/test-lib.pm';
+
+my $res;
+
+init(
+ {
+ logLevel => 'error',
+ useSafeJail => 1,
+ authentication => 'SSL',
+ userDB => 'Null',
+ SSLVar => 'SSL_CLIENT_S_DN_Custom',
+ }
+);
+
+ok(
+ $res = &client->_get(
+ '/', custom => { SSL_CLIENT_S_DN_Custom => 'dwho' }
+ ),
+ 'Auth query'
+);
+ok( $res->[0] == 200, 'Response is 200' ) or explain( $res->[0], 200 );
+my $cookies = getCookies($res);
+my $id;
+ok( $id = $cookies->{lemonldap}, 'Get cookie' )
+ or explain( $res, 'Set-Cookie: something' );
+clean_sessions();
+
+count(3);
+done_testing( count() );