Revision 246
- Date:
- 2012/09/18 18:31:16
- Files:
-
- /utf8/plugins/session/comps/www/oauth/google.html (Diff) (Checkout)
- /utf8/plugins/session/config.proto (Diff) (Checkout)
- /utf8/plugins/session/lib/session/AUTH/Google.pm (Diff) (Checkout)
- /utf8/plugins/session/lib/session/Init.pm (Diff) (Checkout)
- /utf8/plugins/session/lib/session/State.pm.proto (Diff) (Checkout)
Legend:
- Added
- Removed
- Modified
-
utf8/plugins/session/comps/www/oauth/google.html
1 <script type="text/javascript"> 2 <!-- 3 opener.location.reload(true); 4 close(); 5 //--> 6 </script> 7 <pre><% Dumper($google_connect) %></pre> 8 <%doc> 9 10 use LWP::UserAgent; 11 use JSON::XS; 12 use URI; 13 use Encode; 14 use URI; 15 use URI::QueryParam; 16 my $JSON = JSON::XS->new->utf8; 17 18 Manual redirect: 19 use session::AUTH::Google; 20 my $site = $state->development ? 'www' : 'www'; 21 my $google_connect = session::AUTH::Google->new( 22 google_redirect_uri => 'http://'.$site.'/oauth/google.html', 23 ); 24 25 26 </%doc> 27 <%once> 28 29 my $site = $state->development ? '' : ''; 30 use session::AUTH::Google; 31 32 </%once> 33 <%args> 34 35 $code => undef 36 37 </%args> 38 <%init> 39 40 my $res; 41 my $info; 42 43 my $google_connect = session::AUTH::Google->new; 44 my $auth_url = $google_connect->authorize_url; 45 if ( $code ) { 46 my $local_session = $google_connect->authenticate( code => $code ); 47 if ( ref $local_session && exists $local_session->{id} ) { 48 my $profile = $keeper->{users}->get_profile( id => $local_session->{id} ) if exists $keeper->{users}; 49 if ( ref $profile ) { 50 unless ( exists $local_session->{avatar} ) { 51 my $avatar = $profile->get_image('avatar'); 52 $session->{avatar} = ref $avatar && exists $avatar->{filename} ? $avatar->{mini}{'54x54'}{filename} : undef; 53 $keeper->{session}->store_value ( 54 name => $profile->name_full, 55 last_name => $profile->name_family, 56 first_name => $profile->name_part, 57 avatar => $session->{avatar}, 58 ); 59 } else { 60 $keeper->{session}->store_value ( 61 name => $profile->name_full, 62 last_name => $profile->name_family, 63 first_name => $profile->name_part, 64 ); 65 } 66 } 67 } 68 } elsif ( $auth_url ) { 69 $m->redirect($auth_url->as_string); 70 } else { 71 &abort404 unless $DEBUG; 72 } 73 74 </%init> -
utf8/plugins/session/config.proto
77 77 REWRITE += MAILRU_APP_ID MAILRU_APP_SECRET MAILRU_REDIRECT_URL MAILRU_USER_POST_URL 78 78 79 79 80 ### AUTH::Google 81 ###################################### 82 GOOGLE_APP_ID = 83 GOOGLE_APP_SECRET = 84 GOOGLE_REDIRECT_URL = 85 GOOGLE_USER_POST_URL = 86 87 REWRITE += GOOGLE_APP_ID GOOGLE_APP_SECRET GOOGLE_REDIRECT_URL GOOGLE_USER_POST_URL 88 89 # Optional. For email request: 90 GOOGLE_SCOPE = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email 91 REWRITE += GOOGLE_SCOPE 92 80 93 CONNECTION_TIMEOUT = 3 81 94 95 82 96 PROJECT_REQUIRED += Crypt-SSLeay 83 -
utf8/plugins/session/lib/session/AUTH/Google.pm
1 package session::AUTH::Google; 2 3 use strict; 4 use warnings; 5 use LWP::UserAgent; 6 use JSON::XS; 7 use Data::Dumper; 8 use URI; 9 use URI::QueryParam; 10 use Encode; 11 use Digest::MD5 qw/ md5_hex /; 12 use Contenido::Globals; 13 14 use vars qw($VERSION); 15 $VERSION = '4.1'; 16 17 =for rem 18 facebook: 19 auto_create_user: 1 20 app_id: string 21 app_secret: 32 hex digits 22 authorize_url: https://accounts.google.com/o/oauth2/auth 23 access_token_url: https://accounts.google.com/o/oauth2/token 24 user_info_url: https://www.googleapis.com/oauth2/v1/userinfo 25 user_post_url: ~ 26 state: is passed back to your app as a parameter of the redirect_uri when the user completed the authentication 27 store: 28 class: "+Comments::Authentication::Store" 29 type: facebook 30 31 =cut 32 33 our $JSON = JSON::XS->new->utf8; 34 35 =for rem SCHEMA 36 37 $m->redirect ( $g_connect->authorize_url( redirect_uri => ... )->as_string ); 38 39 40 =cut 41 42 43 sub new { 44 my ($class, %config) = @_; 45 my $self = bless {}, $class; 46 47 $self->{google_authorize_url} = 'https://accounts.google.com/o/oauth2/auth'; 48 $self->{google_access_token_url} = 'https://accounts.google.com/o/oauth2/token'; 49 $self->{google_user_info_url} = 'https://www.googleapis.com/oauth2/v2/userinfo'; 50 # $self->{scope} = 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email'; 51 $self->{scope} = $config{scope} || $state->{session}{google_scope} || 'https://www.googleapis.com/auth/userinfo.profile'; 52 53 for (qw(google_app_id google_app_secret)) { 54 $self->{$_} = $config{$_} || $state->{session}{$_} || return undef; 55 } 56 $self->{timeout} = $state->{session}{connection_timeout} || 3; 57 for (qw(google_user_post_url google_redirect_uri)) { 58 $self->{$_} = $config{$_} || $state->{session}{$_}; 59 } 60 return $self; 61 } 62 63 sub authorize_url { 64 my $self = shift; 65 my (%args) = @_; 66 my $go = URI->new( $self->{google_authorize_url} ); 67 $go->query_param( client_id => $self->{google_app_id} ); 68 # $go->query_param( state => $args{state} ) if $args{state}; 69 $go->query_param( response_type => "code" ); 70 $go->query_param( scope => $self->{scope} ); 71 $args{redirect_uri} ||= $self->{google_redirect_uri}; 72 for ( keys %args ) { 73 $go->query_param( $_ => $args{$_} ); 74 } 75 warn Dumper($go) if $DEBUG; 76 return $go; 77 } 78 79 sub authenticate { 80 my ( $self, %authinfo ) = @_; 81 warn "Google.authenticate" if $DEBUG; 82 83 my $local_session = $session || $keeper->{session}->get_session; 84 my $redirect_uri = $self->{google_redirect_uri}; 85 86 my $access_token = $local_session->{google_access_token} || $local_session->{google_refresh_token}; 87 my $expires = $local_session->{google_expires}; 88 if ($access_token and $expires > time) { 89 warn "Already have access_token" if $DEBUG; 90 } else { 91 undef $access_token; 92 } 93 my $code = $authinfo{'code'}; 94 unless ( $code ) { 95 warn "Call to authenticate without code"; 96 return undef; 97 } 98 my $ua = LWP::UserAgent->new; 99 $ua->timeout($self->{timeout}); 100 unless ($access_token) { 101 my $req = URI->new( $self->{google_access_token_url}); 102 my %post_params = ( 103 code => $code, 104 client_id => $self->{google_app_id}, 105 client_secret => $self->{google_app_secret}, 106 redirect_uri => $redirect_uri, 107 grant_type => 'authorization_code', 108 ); 109 warn "Post: $req".Dumper(\%post_params) if $DEBUG; 110 my $res = $ua->post($req, \%post_params); 111 unless ($res->code == 200) { 112 warn "access_token request failed: ".$res->status_line; 113 return undef; 114 } 115 my $info = $JSON->decode($res->content); 116 unless ( ref $info eq 'HASH' && ($access_token = $info->{access_token}) ) { 117 warn "No access token in response: ".$res->content."\n"; 118 return undef; 119 } 120 $keeper->{session}->store_value( 121 google_access_token => $access_token, 122 google_refresh_token => $info->{refresh_token}, 123 ); 124 $local_session->{google_access_token} = $access_token; 125 $local_session->{google_refresh_token} = $info->{refresh_token} if $info->{refresh_token}; 126 if( my $expires = $info->{expires_in} ) { 127 $local_session->{google_expires} = time + $expires; 128 $keeper->{session}->store_value( google_expires => $local_session->{google_expires} ); 129 } else { 130 #$c->user_session->{'expires'} = time + 3600*24; 131 } 132 warn "Google: requested access token: $access_token" if $DEBUG; 133 } else { 134 warn "Google: have access token" if $DEBUG; 135 } 136 137 my $req = URI->new( $self->{google_user_info_url} ); 138 $req->query_param( access_token => $access_token ); 139 $ua->credentials("googleapis.com:80", "Authorization", "Bearer", $access_token); 140 141 warn "Fetching user $req" if $DEBUG; 142 my $res = $ua->get($req); 143 unless ($res->code == 200) { 144 warn "user request failed: ".$res->status_line; 145 return undef; 146 } 147 my $info; 148 unless ( $info = eval { $JSON->decode($res->content) } ) { 149 warn "user '".$res->content."' decode failed: $@"; 150 return undef; 151 } 152 153 foreach my $key ( qw(name family_name given_name) ) { 154 $info->{$key} = Encode::encode('utf-8', $info->{$key}); 155 } 156 warn "Userhash = ".Dumper($info) if $DEBUG; 157 158 my @plugins = split (/[\ |\t]+/, $state->{plugins}); 159 my $name = $info->{name}; 160 if ( grep { $_ eq 'users' } @plugins ) { 161 my $user = $keeper->{users}->get_profile( email => $info->{email} ) if $info->{email}; 162 $user ||= $keeper->{users}->get_profile( login => 'google:'.$info->{id} ); 163 unless ( ref $user ) { 164 my $user_class = $state->{users}->profile_document_class; 165 $user = $user_class->new( $keeper ); 166 $user->login( $info->{email} || 'google:'.$info->{id} ); 167 $user->name( $name ); 168 $user->status( 1 ); 169 $user->type( 0 ); 170 $user->login_method('google'); 171 if ( $info->{locale} ) { 172 $user->country( $info->{locale} ); 173 } 174 if ( $info->{birthday} && $info->{birthday} =~ /(\d{2})\.(\d{2})\.(\d{4})/ ) { 175 $user->dtime( "$3-$2-$1" ); 176 } 177 $user->email( $info->{email} || undef ); 178 179 my ($prop_ava) = grep { $_->{attr} eq 'avatar' && $_->{type} eq 'image' } $user->structure; 180 if ( ref $prop_ava && $info->{picture} ) { 181 my $avatar = $user->_store_image( $info->{picture}, attr => 'avatar' ); 182 $user->avatar( $user->_serialize($avatar) ); 183 } 184 185 $user->store; 186 } else { 187 my ($prop_ava) = grep { $_->{attr} eq 'avatar' && $_->{type} eq 'image' } $user->structure; 188 if ( ref $prop_ava ) { 189 my $avatar = $user->get_image( 'avatar' ); 190 if ( $info->{picture} && !(ref $avatar && exists $avatar->{filename}) ) { 191 my $avatar = $user->_store_image( $info->{picture}, attr => 'avatar' ); 192 $user->avatar( $user->_serialize($avatar) ); 193 $user->store; 194 } 195 } 196 } 197 my %data = ( 198 id => $user->id, 199 name => $user->name, 200 login => $user->login, 201 email => $user->email, 202 status => $user->status, 203 type => $user->type, 204 ltime => time, 205 avatar => $info->{picture}, 206 ); 207 $keeper->{session}->store_value ( %data ); 208 while ( my ( $key, $value ) = each %data ) { 209 $local_session->{$key} = $value; 210 } 211 } else { 212 my %data = ( 213 id => $info->{id}, 214 name => $name, 215 gender => $info->{gender} ? ($info->{gender} eq 'male' ? 'm' : $info->{gender} eq 'female' ? 'f' : undef) : undef, 216 email => $info->{email}, 217 login => $info->{email} || 'google:'.$info->{id}, 218 status => 1, 219 type => 0, 220 auth_by => 'google', 221 ltime => time, 222 ); 223 if ( $user->{picture} ) { 224 $data{avatar} = $info->{picture}; 225 } 226 $keeper->{session}->store_value ( %data ); 227 while ( my ( $key, $value ) = each %data ) { 228 $local_session->{$key} = $value; 229 } 230 } 231 return $local_session; 232 } 233 234 1; -
utf8/plugins/session/lib/session/Init.pm
8 8 use session::AUTH::FaceBook; 9 9 use session::AUTH::VKontakte; 10 10 use session::AUTH::Mailru; 11 use session::AUTH::Google; 11 12 12 13 # загрузка всех необходимых плагину классов 13 14 # session::SQL::SomeTable -
utf8/plugins/session/lib/session/State.pm.proto
56 56 $self->{mailru_redirect_uri} = '@MAILRU_REDIRECT_URL@'; 57 57 $self->{mailru_user_post_url} = '@MAILRU_USER_POST_URL@'; 58 58 59 $self->{google_app_id} = '@GOOGLE_APP_ID@'; 60 $self->{google_app_secret} = '@GOOGLE_APP_SECRET@'; 61 $self->{google_redirect_uri} = '@GOOGLE_REDIRECT_URL@'; 62 $self->{google_user_post_url} = '@GOOGLE_USER_POST_URL@'; 63 $self->{google_scope} = '@GOOGLE_SCOPE@'; 64 59 65 $self->_init_(); 60 66 $self; 61 67 }