Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I realize this is more of a Movable Type issue than a perl issue, but the MT Forum hasn't been any help and now I'm starting to think I've screwed up the code that does the heavy lifting which is in perl. So I'm asking here and hope it is considered on topic.

We have a Movable Type Blog. I want to require Authenticated commenters only. Instead of using the default typekey.com to handle identy verification, I want to use our own inhome typekey like system.

I read http://www.sixapart.com/typekey/api

It seemed simple enough. I did have a little trouble in that I couldn't figure out how to do the DSA stuff in PHP. So what I do is have them go to a php form. This form submits data to another php page. This 2nd page checks the username and password with the database. if valid it does an exec and runs a perl script which generates the return URL with all the parameters and passes it back to the 2nd page. The 2nd page once it has the return URL, sets a few $_SESSION variables (for use with other parts of the stie not related to MT) and then redirects to the return URL.

Now everything seems to work until the user is redirected back to MT. Where they get "The sign-in validation failed."

Accodring to the comments in the code this happens

# Signature didn't match, or timestamp was out of date. # This implies tampering, not a user mistake.
To eliminate the timestamp being out of date I modified the MT code and set $SIG_WINDOW = 60*60*24*365; and still get the error.

Soooo this must mean the signature doesn't match. In trying to trying to figure out why, I found I had a number of problems which I have since fixed. As far as I can tell the following items are all correct:

* SignOnURL, SignOffURL, RegKeyURL, and IdentityURL in mt-config.cgi are all set correctly

* MT is using the correct key from my site (and not from typekey).

* It appears that MT is getting the values I'm passing to it (it just doesn't seem to think they are correct).

* With $SIG_WINDOW set so high, I'm pretty sure the timestamp is not out of date. I've also run a few tests to see how the timestamp compairs to what MT thinks the time is and the largest difference has been 4 seconds.

The key was created with a very simple code that I ran from the command line.

#!/usr/bin/perl use lib '/home/httpd/typekey/perl/share/perl/5.8.4'; # this is where C +rypt::DSA is use Crypt::DSA; my $dsa = Crypt::DSA->new; my $key = $dsa->keygen(Size => 512, Verbosity => 1); print ref $key; foreach my $k (keys %{$key}) { print "\n\n" . $k . " ==> " . $key->$k . "\n\n"; } $key->write(Type => PEM, Filename => "./pem.txt");
Then I stuffed the onscreen output in the right format into a text file (same one in RegKeysURL in mt-config.cgi). Here's the regkey.txt file:
p=97247750263688411397695697227222252821052653116602457842628843398397 +774090219841943394778088386502591291192911110236855402879198647672438 +25053675926821009 g=2287671994688384782344874533763258286273033538675 +213553369081285149300964884679721477594029701967288779349370846813565 +354155329221817904945538359260835488 q=859065163383488309172119698913 +578680476929548109 pub_key=161640584437224876801717508172571581946779 +447648116511124702069752318953966274857590303105635724984838115717840 +0231796838322469179029084738638486691222852
Here's the pem.txt file:
-----BEGIN DSA PRIVATE KEY----- MIH3AgEAAkEAua21zY9vkrbyBe4b+XeGCLBEPCinaRsDidZnYcXznjiE25KWzaez 27m/CYaM3jEZPsP8InkmmCsWixz6R4uYkQIVAJZ50HBdIVUFssSLwqpyOa3cut9N AkArrehkdlnDRs1EFomRowMUuZX/52nsY56+RZAtrmuhJ1Qp5cZzDBQcF7oLZE9J tbUzTuCf0ufn0v9ZG+ZD/26gAkAe3NPCjj9sycSdcpYBkFH6+6PmPh+ZucgGExNa 7KUGtG3hs9RMkZeEKN4WSbi9AgMFuiYzvO814AusboSImZVEAhQ0kb43UjYzfSug ByFFsKZhRyay1g== -----END DSA PRIVATE KEY-----
Here's the priv_key:
priv_key ==> 300117698295761934718759909833610346650914960086

Yes after I get this working, I will generate a new key.

So now on to the script that does the heavy lifting...here's my code that creates the URL which the user is redirected back to MT to complete the comment login.

#!/usr/bin/perl use strict; + use lib '/home/httpd/typekey/perl/share/perl/5.8.4'; # this is where C +rypt::DSA is + use Crypt::DSA; + use CGI; use Crypt::DSA::Key; # found on random google group use MIME::Base64; my ($t, $need_email, $_return, $v, $email, $name, $nick) = @ARGV; # $t is the site token, should be passed from logon.php # $need_email, should be 1 and should be passed from logon.php # $_return, is the base URL to append the other parameters to. NOTE: +It already has a ? and a number of other parameters # $v, typekey version should be 1.1 and passed from logon.php # $email, user's email logon.php got this from the database # $name, user's userid. logon.php got this from the database # $nick, user's display name logon.php got this from the database my($ts, $sig); # $ts, timestamp # $sig the sig of the message before we break out r & s + $ts = time; + my $sig_msg = "$email::$name::$nick::$ts::$t"; # this is the message +to be signed. + my $dsa = Crypt::DSA->new; + my $key = Crypt::DSA::Key->new( Type => 'PEM', Filename => '/home/httpd/typekey/pem.txt'); + $sig = $dsa->sign(Message=>$sig_msg, Key => $key); # my $sig_typekey = $sig->r . ":" . $sig->s; my $sig_typekey = encode_base64($sig->r, "") . ":" . encode_base64($si +g->s, ""); + my $full_url = $_return . "&email=" . CGI::escape($email) . "&name=" . + CGI::escape($name) . "&nick=" . CGI::escape($nick) . "&ts=" . CGI::e +scape($ts) . "&sig=" . CGI::escape($sig_typekey); print $full_url; #print the new URL so logon.php can pick it up and r +edirect to it.
If you're interested in all of the trials and tribulations I've had with this check out: http://www.sixapart.com/movabletype/forums/index.php?showtopic=58124

Please I hope someone can figure out what I'm doing wrong. Thanks in advance.

Replies are listed 'Best First'.
Re: Typekey API
by japhy (Canon) on May 30, 2006 at 16:45 UTC
    You don't have warnings turned on, which means you're not going to be warned about all the undefined variables on this line:
    my $sig_msg = "$email::$name::$nick::$ts::$t"; # this is the message +to be signed.
    Perl reads that as:
    my $sig_msg = $email:: . $name:: . $nick:: . $ts:: . $t;
    because "::" is the package separator an it is legal to have a variable with an "empty" name like $foo:: (the "" scalar in package 'foo'). I suggest replacing the line with
    my $sig_msg = join "::", $email, $name, $nick, $ts, $t;
    and turning warnings on, too. Apart from this, I don't know what to tell you about your problem.

    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
      Thanks! I didn't know about the problem with using :: inside quotes. Shouldn't you have the same problem in with the join statement?

      Anyway after making this change the script runs find even using warnings. However, I'm still getting the exact same error with MT. So it still doesn't like what I'm sending it. :(