| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- #!/usr/bin/perl
- use Modern::Perl;
- # Авторизация для Дарсана
- # Ю. Жиловец, 17.02.2015
- package darsan_auth;
- use Crypt::OpenSSL::RSA;
- use Mojo::JSON qw/j/;
- use Mojo::UserAgent;
- use Convert::Ascii85 qw/ascii85_encode/;
- use Time::timegm qw/timegm/;
- use POSIX::strptime;
- use Data::Dumper;
- use Mojo::Promise;
- sub error
- {
- return $_[0]->{error};
- }
- sub source_ip
- {
- my $self = shift;
- my $ip = shift;
- $self->{ua}->local_address($ip);
- }
- sub as_server
- {
- my $class = shift;
- my $auth_servers = shift;
- my $name = shift;
- my $private = shift;
- if (ref($private) ne "Crypt::OpenSSL::RSA")
- {
- open(K,$private) or do die "No private key found: $private: $!";
- my $key = do { local($/); <K>};
- close(K);
- $private = Crypt::OpenSSL::RSA->new_private_key($key);
- $private->use_sha1_hash;
- $private->use_pkcs1_padding;
- }
- $auth_servers = [ $auth_servers ] unless ref $auth_servers;
- return bless {auth_servers=>$auth_servers, name=>$name, private=>$private, error=>undef, ua=>new Mojo::UserAgent},$class;
- }
- sub as_user
- {
- my $class = shift;
- my $auth_servers = shift;
- my $login = shift;
- my $password = shift;
- $auth_servers = [ $auth_servers ] unless ref $auth_servers;
- return bless {auth_servers=>$auth_servers, login=>$login, password=>$password, error=>undef, ua=>new Mojo::UserAgent},$class;
- }
- sub set_token
- {
- my $self = shift;
- my $token = shift;
- my $exp_stamp = shift;
- $self->{token} = $token;
- $self->{expire} = $exp_stamp;
- }
- sub token
- {
- my $self = shift;
- my $sub = shift;
-
- my $deferred;
- if ($sub && $sub eq "promise")
- {
- $deferred = new Mojo::Promise;
- $sub = sub {
- my ($err,$body) = @_;
- if ($err)
- {
- $deferred->reject($err);
- }
- else
- {
- $deferred->resolve($body);
- }
- };
- }
- undef $self->{error};
- if ($self->{token} && $self->{expire}>time())
- {
- if ($sub)
- {
- $sub->(undef,$self->{token});
- return $deferred;
- }
- else
- {
- return $self->{token};
- }
- }
- if ($sub)
- {
- $self->_token(sub {
- my ($err,$token,$expire) = @_;
- if ($err)
- {
- $self->{error} = $err;
- return $sub->($err);
- }
- $self->{token} = $token;
- $self->{expire} = $expire;
- $sub->(undef,$token);
- });
- return $deferred;
- }
- else
- {
- my ($err,$token,$expire) = $self->_token;
- if ($err)
- {
- $self->{error} = $err;
- return undef;
- }
- $self->{token} = $token;
- $self->{expire} = $expire;
- return $token;
- }
- }
- sub _token
- {
- my $self = shift;
- my $sub = shift;
- if ($self->{login})
- {
- return $self->_fetch_token($sub, "token",
- {ver=>2, login=>$self->{login}, password=>$self->{password}} );
- }
- else
- {
- my $t = time();
- my $sign = $self->{private}->sign("$self->{name}/$t");
- return $self->_fetch_token($sub, "server-token/$self->{name}",
- {ver=>2, time=>$t, sign=>ascii85_encode($sign)} );
- }
- }
- sub _fetch_token
- {
- my $self = shift;
- my $sub = shift;
- my $url = shift;
- my $form = shift;
- if ($sub)
- {
- $self->_fetch_token_async($sub,$url,$form);
- }
- else
- {
- $self->_fetch_token_sync($url,$form);
- }
- }
- sub _fetch_token_sync
- {
- my $self = shift;
- my $url = shift;
- my $form = shift;
- my $tx;
- LOOP: {
- foreach my $server (@{ $self->{auth_servers} })
- {
- $tx = $self->{ua}->post("$server/$url" => form => $form);
- last LOOP if $tx->result;
- last if $tx->error && $tx->error->{status} && $tx->error->{status}==400;
- }
- my $e = $tx->error;
- $e->{code} ||= 500;
- my $err = {code=>$e->{code}, message=> $e->{message}, body => $tx->res->body};
- return ($err);
- }
- my $body = j($tx->res->body);
- my $token = $body->{token};
- my $expires = $body->{expires};
- my $exp = $self->parse_time($expires);
- return (undef,$token,$exp);
- }
- sub _fetch_token_async
- {
- my $self = shift;
- my $sub = shift;
- my $url = shift;
- my $form = shift;
- my $server = $self->{auth_servers}->[0];
- $self->{ua}->post_p("$server/$url" => form => $form)
- ->then(sub
- {
- my $tx = shift;
-
- if (my $e = $tx->error)
- {
- return $sub->( {code=>$e->{code}, url=>"$server/$url", message=>$e->{message}, body=>$tx->result->body} );
- }
-
- my $body = j($tx->result->body);
- my $token = $body->{token};
- my $expires = $body->{expires};
- my $exp = $self->parse_time($expires);
- $sub->(undef,$token,$exp);
- })
- ->catch(sub
- {
- my $e = shift;
- unless (ref $e)
- {
- $sub->( {code=>500, url=>"$server/$url", message=>$e, body=>""} );
- }
- else
- {
- $e->{code} ||= 500;
- $sub->( {code=>$e->{code}, url=>"$server/$url", message=>$e->{message}, body=>""} );
- }
- });
- }
- sub parse_time
- {
- no warnings;
- my $self = shift;
- my $s = shift;
- $s =~ /([+-])(\d{4})$/;
- my $tz_sign = $1;
- my $tz = $2;
- $s =~ s/[+-]\d{4}$//;
- my $time = timegm(POSIX::strptime($s,"%Y-%m-%d %H:%M:%S%z"));
- if ($tz)
- {
- my $h = substr($tz,0,2);
- my $s = substr($tz,2,2);
- my $offset = ($h*60+$s)*60;
- $offset = -$offset if $tz_sign eq "+";
- $time += $offset;
- }
- return $time;
- }
- 1;
|