google account export tweaks, #11760
authormark <mark>
Wed, 16 Mar 2011 01:43:29 +0000 (01:43 +0000)
committermark <mark>
Wed, 16 Mar 2011 01:43:29 +0000 (01:43 +0000)
FS/FS/part_export/acct_google.pm
httemplate/edit/process/svc_acct.cgi
httemplate/edit/svc_acct.cgi

index 748ea57..f7a1181 100644 (file)
@@ -88,6 +88,23 @@ sub _export_unsuspend {
   );
 }
 
+sub captcha_url {
+  my $self = shift;
+  my $google = $self->google_handle;
+  if (exists ($google->{'captcha_url'}) ) {
+    return 'http://www.google.com/accounts/'.$google->{'captcha_url'};
+  }
+  else {
+    return '';
+  }
+}
+
+sub captcha_auth {
+  my $self = shift;
+  my $response = shift;
+  my $google = $self->google_handle('captcha_response' => $response);
+  return (defined($google->{'token'}));
+}
 
 my %google_error = (
   1000 => 'unknown error',
@@ -113,7 +130,9 @@ my %google_error = (
 
 sub google_request {
   my ($self, $method, %opt) = @_;
-  my $google = $self->google_handle;
+  my $google = $self->google_handle(
+    'captcha_response' => delete $opt{'captcha_response'}
+  );
   return $google->{'error'} if $google->{'error'};
 
   # Throw away the result from this; we don't use it yet.
@@ -133,6 +152,7 @@ sub google_request {
 sub google_handle {
   my $self = shift;
   my $class = 'REST::Google::Apps::Provisioning';
+  my %opt = @_;
   eval "use $class";
 
   die "failed to load $class\n" if $@;
@@ -167,24 +187,71 @@ sub google_handle {
     }
   );
 
-  my $cache_id = $self->exportnum . '_token';
-  $google->{'token'} = $CACHE->get($cache_id);
+  my $cache_token = $self->exportnum . '_token';
+  my $cache_captcha = $self->exportnum . '_captcha_token';
+  $google->{'token'} = $CACHE->get($cache_token);
   if ( !$google->{'token'} ) {
-    eval { 
-      $google->authenticate(
-        'username'  => $self->option('username'),
-        'password'  => $self->option('password'),
-      ) 
-    };
+    my %login = (
+      'username' => $self->option('username'),
+      'password' => $self->option('password'),
+    );
+    if ( $opt{'captcha_response'} ) {
+      $login{'logincaptcha'} = $opt{'captcha_response'};
+      $login{'logintoken'} = $CACHE->get($cache_captcha);
+    }
+    eval { $google->captcha_auth(%login); };
     if ( $@ ) {
-      # XXX CAPTCHA
       $google->{'error'} = $@->{'error'};
-      $CACHE->remove($cache_id);
+      $google->{'captcha_url'} = $@->{'captchaurl'};
+      $CACHE->set($cache_captcha, $@->{'captchatoken'}, '1 minute');
       return $google;
     }
-    $CACHE->set($cache_id, $google->{'token'}, '1 hour');
+    $CACHE->remove($cache_captcha);
+    $CACHE->set($cache_token, $google->{'token'}, '1 hour');
   }
   return $google;
 }
 
+# REST::Google::Apps::Provisioning also lacks a way to do this
+sub REST::Google::Apps::Provisioning::captcha_auth {
+  my $self = shift;
+
+  return( 1 ) if $self->{'token'};
+
+  my ( $arg );
+  %{$arg} = @_;
+
+  map { $arg->{lc($_)} = $arg->{$_} } keys %{$arg};
+
+  foreach my $param ( qw/ username password / ) {
+    $arg->{$param} || croak( "Missing required '$param' argument" );
+  }
+
+  my @postargs = (
+    'accountType' => 'HOSTED',
+    'service'     => 'apps',
+    'Email'       => $arg->{'username'} . '@' . $self->{'domain'},
+    'Passwd'      => $arg->{'password'},
+  );
+  if ( $arg->{'logincaptcha'} ) {
+    push @postargs, 
+      'logintoken'  => $arg->{'logintoken'},
+      'logincaptcha'=> $arg->{'logincaptcha'}
+      ;
+  }
+  my $response = $self->{'lwp'}->post(
+    'https://www.google.com/accounts/ClientLogin',
+    \@postargs
+  );
+
+  $response->is_success() || return( 0 );
+
+  foreach ( split( /\n/, $response->content() ) ) {
+    $self->{'token'} = $1 if /^Auth=(.+)$/;
+    last if $self->{'token'};
+  }
+
+  return( 1 ) if $self->{'token'} || return( 0 );
+}
+
 1;
index 52701df..a7d5136 100755 (executable)
@@ -56,31 +56,47 @@ my $new = new FS::svc_acct ( \%hash );
 
 my $error = '';
 
+# google captcha auth
+if ( $cgi->param('captcha_response') ) {
+  my $part_svc = $svcnum ? 
+                  $old->part_svc : 
+                  qsearchs( 'part_svc', 
+                    { 'svcpart' => $cgi->param('svcpart') }
+                  );
+  my ($export) = $part_svc->part_export('acct_google');
+  if ( $export and
+      ! $export->captcha_auth($cgi->param('captcha_response')) ) { 
+    $error = 'Re-enter the security word.';
+  }
+}
+
 $new->_password($old->_password) if $old;
 if (     $cgi->param('clear_password') eq '*HIDDEN*'
       || $cgi->param('clear_password') =~ /^\(.* encrypted\)$/ ) {
   die "fatal: no previous account to recall hidden password from!" unless $old;
 } else {
-  $error = $new->set_password($cgi->param('clear_password'));
+  $error ||= $new->set_password($cgi->param('clear_password'));
 }
 
-if ( $svcnum ) {
-  foreach ( grep { $old->$_ != $new->$_ }
-                 qw( seconds upbytes downbytes totalbytes )
-          )
-  {
-    my %hash = map { $_ => $new->$_ } 
-               grep { $new->$_ }
-               qw( seconds upbytes downbytes totalbytes );
+if ( ! $error ) {
+  if ( $svcnum ) {
+    foreach ( grep { $old->$_ != $new->$_ }
+                   qw( seconds upbytes downbytes totalbytes )
+            )
+    {
+      my %hash = map { $_ => $new->$_ } 
+                 grep { $new->$_ }
+                 qw( seconds upbytes downbytes totalbytes );
 
-    $error ||= "invalid $_" foreach grep { $hash{$_} !~ /^-?\d+$/ } keys %hash;
-    $error ||= $new->set_usage(\%hash);  #unoverlimit and trigger radius changes
-    last;                                #once is enough
+      $error ||= "invalid $_" foreach grep { $hash{$_} !~ /^-?\d+$/ } keys %hash;
+      $error ||= $new->set_usage(\%hash);  #unoverlimit and trigger radius changes
+      last;                                #once is enough
+    }
+    $error ||= $new->replace($old);
+  } else {
+    $error ||= $new->insert;
+    $svcnum = $new->svcnum;
   }
-  $error ||= $new->replace($old);
-} else {
-  $error ||= $new->insert;
-  $svcnum = $new->svcnum;
 }
 
 </%init>
index 0a191b4..2eb4a8b 100755 (executable)
@@ -340,6 +340,12 @@ Service # <% $svcnum ? "<B>$svcnum</B>" : " (NEW)" %><BR>
 </TABLE>
 <BR>
 
+% if ( $captcha_url ) {
+<IMG SRC="<% $captcha_url %>"><BR>
+Enter the word shown above: <INPUT TYPE="text" NAME="captcha_response"><BR>
+<BR>
+% }
+
 <INPUT TYPE="submit" VALUE="Submit">
 
 </FORM>
@@ -485,4 +491,10 @@ sub max {
   (sort(@_))[-1]
 }
 
+my $captcha_url;
+my ($export_google) = $part_svc->part_export('acct_google');
+if ( $export_google ) {
+  $captcha_url = $export_google->captcha_url || '';
+}
+
 </%init>