Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Projets publics
Ravada-Mirror
Commits
45e0669d
Commit
45e0669d
authored
Apr 12, 2021
by
Francesc Guasch
Browse files
Merge branch 'develop' of github.com:UPC/ravada into develop
parents
53d7f388
d6499ab1
Changes
4
Hide whitespace changes
Inline
Side-by-side
lib/Ravada/Auth.pm
View file @
45e0669d
...
...
@@ -4,6 +4,7 @@ use warnings;
use
strict
;
our
$LDAP_OK
;
our
$SSO_OK
;
use
Ravada::Auth::
SQL
;
...
...
@@ -32,6 +33,19 @@ sub init {
}
else
{
$LDAP_OK
=
0
;
}
if
(
$config
->
{
sso
}
&&
(
!
defined
$SSO_OK
||
$SSO_OK
)
)
{
eval
{
$SSO_OK
=
0
;
require
Ravada::Auth::
SSO
;
Ravada::Auth::SSO::
init
(
$config
);
$SSO_OK
=
1
;
};
warn
$@
if
$@
;
}
else
{
$SSO_OK
=
0
;
}
# Ravada::Auth::SQL::init($config, $db_con);
}
...
...
@@ -64,6 +78,31 @@ sub login {
return
$sql_login
;
}
=head2 login_external
Tries login_external in all the submodules
my $ok = Ravada::Auth::login_external();
=cut
sub
login_external
{
my
(
$ticket
,
$cookie
,
$quiet
)
=
@_
;
my
$login_ok
;
if
(
!
defined
$SSO_OK
||
$SSO_OK
)
{
eval
{
$login_ok
=
Ravada::Auth::SSO::
login_external
(
$ticket
,
$cookie
);
};
warn
$@
if
$@
&&
$SSO_OK
&&
!
$quiet
;
if
(
$login_ok
)
{
$login_ok
->
{'
mode
'}
=
'
external
';
return
$login_ok
;
}
}
return
undef
;
}
=head2 enable_LDAP
Sets or get LDAP support.
...
...
@@ -81,4 +120,23 @@ sub enable_LDAP {
$LDAP_OK
=
$value
;
return
$value
;
}
=head2 enable_CAS
Sets or get CAS support.
Ravada::Auth::enable_CAS(0);
print "SSO is supported" if Ravada::Auth::enable_SSO();
=cut
sub
enable_SSO
{
my
$value
=
shift
;
return
$SSO_OK
if
!
defined
$value
;
$SSO_OK
=
$value
;
return
$value
;
}
1
;
lib/Ravada/Auth/SSO.pm
0 → 100644
View file @
45e0669d
package
Ravada::Auth::
SSO
;
use
strict
;
use
warnings
;
use
Data::
Dumper
;
use
Authen::
ModAuthPubTkt
;
use
URI::
Escape
;
use
LWP::
UserAgent
;
=head1 NAME
Ravada::Auth::SSO - SSO library for Ravada
=cut
use
Moose
;
no
warnings
"
experimental::signatures
";
use
feature
qw(signatures)
;
use
Ravada::Auth::
SQL
;
with
'
Ravada::Auth::User
';
our
$CONFIG
=
\
$
Ravada::
CONFIG
;
sub
BUILD
{
my
$self
=
shift
;
my
(
$params
)
=
@_
;
die
'
ERROR: Ticket not found
'
if
!
$params
->
{
ticket
};
$self
->
{
ticket
}
=
$params
->
{
ticket
};
$self
->
{
logoutURL
}
=
sprintf
('
%s/logout?service=%s
',
$$CONFIG
->
{
sso
}
->
{
url
},
uri_escape
(
$$CONFIG
->
{
sso
}
->
{
service
}))
if
(
$$CONFIG
->
{
sso
}
->
{
logout
});
die
sprintf
('
ERROR: Login failed %s
',
$self
->
name
)
if
!
$self
->
login
;
return
$self
;
}
sub
add_user
($name, $password, $storage='rfc2307', $algorithm=undef) {
}
sub
remove_user
{
}
sub
search_user
{
}
sub
_check_user_profile
{
my
$self
=
shift
;
my
$user_sql
=
Ravada::Auth::
SQL
->
new
(
name
=>
$self
->
name
);
if
(
$user_sql
->
id
)
{
if
(
$user_sql
->
external_auth
ne
'
sso
')
{
$user_sql
->
external_auth
('
sso
');
}
return
;
}
Ravada::Auth::SQL::
add_user
(
name
=>
$self
->
name
,
is_external
=>
1
,
is_temporary
=>
0
,
external_auth
=>
'
sso
');
}
sub
_generate_session_ticket
{
my
(
$name
)
=
@_
;
my
$cookie
;
die
'
Can
\'
t read privkey file (sso->cookie->priv_key value at ravada.conf file)
'
if
(
!
-
r
$$CONFIG
->
{
sso
}
->
{
cookie
}
->
{
priv_key
});
eval
{
$cookie
=
Authen::ModAuthPubTkt::
pubtkt_generate
(
privatekey
=>
$$CONFIG
->
{
sso
}
->
{
cookie
}
->
{
priv_key
},
keytype
=>
$$CONFIG
->
{
sso
}
->
{
cookie
}
->
{
type
},
userid
=>
$name
,
validuntil
=>
time
()
+
$$CONFIG
->
{
sso
}
->
{
cookie
}
->
{
timeout
});
};
return
$cookie
;
}
sub
_get_session_userid_by_ticket
{
my
(
$cookie
)
=
@_
;
my
$result
;
die
'
Can
\'
t read pubkey file (sso->cookie->pub_key value at ravada.conf file)
'
if
(
!
-
r
$$CONFIG
->
{
sso
}
->
{
cookie
}
->
{
pub_key
});
eval
{
$result
=
Authen::ModAuthPubTkt::
pubtkt_verify
(
publickey
=>
$$CONFIG
->
{
sso
}
->
{
cookie
}
->
{
pub_key
},
keytype
=>
$$CONFIG
->
{
sso
}
->
{
cookie
}
->
{
type
},
ticket
=>
$cookie
);
};
die
$@
?
$@
:
'
Cannot validate ticket
'
if
((
!
$result
)
||
(
$@
));
my
%data
=
Authen::ModAuthPubTkt::
pubtkt_parse
(
$cookie
);
die
'
Ticket is expired
'
if
(
$data
{
validuntil
}
<
time
());
return
$data
{
uid
};
}
sub
_validate_ticket
{
my
(
$ticket
)
=
@_
;
my
$response
=
LWP::
UserAgent
->
new
->
get
(
sprintf
('
%s/serviceValidate?service=%s&ticket=%s
',
$$CONFIG
->
{
sso
}
->
{
url
},
uri_escape
(
$$CONFIG
->
{
sso
}
->
{
service
}),
uri_escape
(
$ticket
)));
return
$
1
if
(
$response
->
content
=~
/<cas:user>(.+)<\/cas:user>/
);
die
sprintf
('
Ticket validation error: %s
',
$response
->
content
);
}
sub
login
($self) {
my
$userid
=
_get_session_userid_by_ticket
(
$self
->
{
ticket
});
die
'
Ticket user id do not coincides with received user id
'
if
(
$self
->
name
ne
$userid
);
return
$self
->
name
;
}
sub
login_external
($ticket, $cookie) {
if
(
$cookie
)
{
my
$name
=
_get_session_userid_by_ticket
(
$cookie
);
my
$self
=
Ravada::Auth::
SSO
->
new
(
name
=>
$name
,
ticket
=>
$cookie
);
$self
->
_check_user_profile
();
return
$self
;
}
elsif
(
$ticket
)
{
my
$name
=
_validate_ticket
(
$ticket
);
my
$self
=
Ravada::Auth::
SSO
->
new
(
name
=>
$name
,
ticket
=>
_generate_session_ticket
(
$name
));
$self
->
_check_user_profile
();
return
$self
;
}
else
{
return
{
redirectTo
=>
sprintf
('
%s/login?service=%s
',
$$CONFIG
->
{
sso
}
->
{
url
},
uri_escape
(
$$CONFIG
->
{
sso
}
->
{
service
}))
};
}
}
sub
is_admin
{
}
sub
is_external
{
}
sub
init
{
}
1
;
script/rvd_front
View file @
45e0669d
...
...
@@ -258,8 +258,8 @@ any '/test' => sub {
any '/logout' => sub {
my $c = shift;
logout($c);
$c->redirect_to('/');
my $redirect_to =
logout($c);
$c->redirect_to(
$redirect_to ? $redirect_to :
'/');
};
get '/anonymous' => sub {
...
...
@@ -2014,19 +2014,30 @@ sub login($c, $status=200) {
my $login = $c->param('login');
my $password = $c->param('password');
my $ticket = $c->param('ticket');
my $url = ($c->param('url') or $c->req->url->to_abs->path);
$url = '/' if $url =~ m{^/login};
my @error =();
if (defined $login || defined $password || $c->param('submit')) {
if
((
(defined $login
)
||
(
defined $password
)
||
((defined
$c->param('submit'))
&&
($c->param('submit') ne 'sso')))
&&
(! $ticket))
{
push @error,("Empty login name") if !length $login;
push @error,("Empty password") if !length $password;
}
my $auth_ok;
if (!@error) {
if (defined $login
&&
defined $password) {
eval { $auth_ok = Ravada::Auth::login($login, $password)};
} elsif (($c->param('ticket')) || ($c->param('submit') eq 'sso')) {
eval { $auth_ok = Ravada::Auth::login_external($ticket, $c->session('ticket')) };
if ($auth_ok
&&
!$@) {
return $c->redirect_to($auth_ok->{'redirectTo'}) if ($auth_ok->{'redirectTo'});
$c->session('ticket' => $auth_ok->{'ticket'}) if ($auth_ok->{'ticket'});
$c->session('logoutURL' => $auth_ok->{'logoutURL'}) if ($auth_ok->{'logoutURL'});
$login = $auth_ok->name;
}
}
if ( !@error
&&
defined $login
&&
defined $password) {
my $auth_ok;
eval { $auth_ok = Ravada::Auth::login($login, $password)};
if ( $auth_ok
&&
!$@) {
$c->session('login' => $login);
my $expiration = $SESSION_TIMEOUT;
...
...
@@ -2050,7 +2061,7 @@ sub login($c, $status=200) {
$c->session(auto_view => $auto_view, expiration => $expiration);
app->log->info("Access granted to $login from "._remote_ip($c)) if $CONFIG_FRONT->{log}->{log};
return $c->redirect_to($url);
} els
e
{
} els
if (defined $c->param('submit'))
{
app->log->error("Access denied to $login from "._remote_ip($c)) if $CONFIG_FRONT->{log}->{log};
push @error,("Access denied");
}
...
...
@@ -2072,6 +2083,7 @@ sub login($c, $status=200) {
,navbar_custom => 1
,login => $login
,error => \@error
,sso_available => $Ravada::Auth::SSO_OK,
,login_header => $CONFIG_FRONT->{login_header}
,login_message => $CONFIG_FRONT->{login_message}
,guide => $CONFIG_FRONT->{guide}
...
...
@@ -2089,7 +2101,12 @@ sub logout {
sleep 1;
$c->session(expires => 0);
$c->session(login => undef);
$c->session(ticket => undef);
my $logout_url = $c->session('logoutURL');
$c->session(logoutURL => undef);
return $logout_url;
}
sub quick_start {
...
...
@@ -2099,25 +2116,39 @@ sub quick_start {
my $login = $c->param('login');
my $password = $c->param('password');
my $ticket = $c->param('ticket');
my $id_base = $c->param('id_base');
my @error =();
if ($c->param('submit')) {
if
(
($c->param('submit')
ne 'sso')
&&
(! $ticket)
) {
push @error,("Empty login name") if !length $login;
push @error,("Empty password") if !length $password;
}
if (defined $ticket) {
push @error, ("Empty ticket value") if !length $ticket;
}
if (
$login
&&
$password
) {
if (
!@error
) {
my $log_ok;
eval { $log_ok = Ravada::Auth::login($login, $password) };
if ($log_ok) {
if ( $login
&&
$password) {
eval { $log_ok = Ravada::Auth::login($login, $password) };
} elsif (($c->param('ticket')) || ($c->param('submit') eq 'sso')) {
eval { $log_ok = Ravada::Auth::login_external($ticket, $c->session('ticket')) };
if ($log_ok
&&
!$@) {
return $c->redirect_to($log_ok->{'redirectTo'}) if ($log_ok->{'redirectTo'});
$c->session('ticket' => $log_ok->{'ticket'}) if ($log_ok->{'ticket'});
$c->session('logoutURL' => $log_ok->{'logoutURL'}) if ($log_ok->{'logoutURL'});
$login = $log_ok->name;
}
}
if ($log_ok
&&
!$@) {
$c->session('login' => $login);
} else {
push @error,("Access denied");
logout($c);
return login($c);
}
else {
push @error,($@ ? $@ : "Access denied");
}
}
if ( $c->param('submit')
&&
_logged_in($c)
&&
defined $id_base ) {
return quick_start_domain($c, $id_base, ($login or $c->session('login')));
...
...
templates/main/start.html.ep
View file @
45e0669d
...
...
@@ -13,9 +13,9 @@
<input
class=
"form-control"
id=
"user"
name=
"login"
value =
"<%= $login %>"
type=
"text"
placeholder=
"<%=l 'User' %>"
required
autofocus
>
<input
class=
"form-control"
id=
"pssw"
type=
"password"
name=
"password"
value=
""
placeholder=
"<%=l 'Password' %>"
required
>
<input
type=
"hidden"
name=
"url"
value=
"<%= $url %>"
>
<input
type=
"hidden"
name=
"url"
value=
"<%= $url %>"
>
<!-- <input type="submit" name="submit" value="launch"> -->
<button
id=
"submit"
class=
"btn btn-success btn-lg btn-block"
href=
"/"
type=
"submit"
name=
"submit"
value=
"launch"
><
%=
l
'
Login
'
%
></button>
<button
id=
"submit"
class=
"btn btn-success btn-lg btn-block"
href=
"/"
type=
"submit"
name=
"submit"
value=
"launch"
><
%=
l
'
Login
with
user
/
password
'
%
></button>
% if (scalar @$error) {
% for my $i (@$error) {
<div
class=
"alert alert-danger"
>
...
...
@@ -24,6 +24,12 @@
% }
% }
</form>
<form
class=
"form-singin"
method=
"post"
>
<input
type=
"hidden"
name=
"url"
value=
"<%= $url %>"
>
% if ($sso_available) {
<button
id=
"submit"
class=
"btn btn-success btn-lg btn-block"
href=
"/"
type=
"submit"
name=
"submit"
value=
"sso"
><
%=
l
'
SSO
/
CAS
Login
'
%
></button>
% }
</form>
<div
class=
"alert alert-warning"
>
<
%=
l
'
A
viewer
is
required
to
run
the
virtual
machines.
'
%
>
<a
href=
"/requirements"
><
%=
l
'
Read
more.
'
%
></a>
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment