summaryrefslogtreecommitdiff
path: root/IkiWiki/Plugin/openid.pm
blob: f43c4db7ffc8806f1ba09e79c6d09757f6aa8484 (plain)
  1. #!/usr/bin/perl
  2. # OpenID support.
  3. package IkiWiki::Plugin::openid;
  4. use warnings;
  5. use strict;
  6. use IkiWiki;
  7. sub import { #{{{
  8. hook(type => "getopt", id => "openid", call => \&getopt);
  9. hook(type => "auth", id => "openid", call => \&auth);
  10. hook(type => "formbuilder_setup", id => "openid",
  11. call => \&formbuilder_setup, last => 1);
  12. } # }}}
  13. sub getopt () { #{{{
  14. eval q{use Getopt::Long};
  15. error($@) if $@;
  16. Getopt::Long::Configure('pass_through');
  17. GetOptions("openidsignup=s" => \$config{openidsignup});
  18. } #}}}
  19. sub formbuilder_setup (@) { #{{{
  20. my %params=@_;
  21. my $form=$params{form};
  22. my $session=$params{session};
  23. my $cgi=$params{cgi};
  24. if ($form->title eq "signin") {
  25. $form->field(
  26. name => "openid_url",
  27. label => "OpenID",
  28. size => 30,
  29. comment => '('.
  30. htmllink("", "", "OpenID", 1, 0, gettext("What's this?"))
  31. .($config{openidsignup} ? " | <a href=\"$config{openidsignup}\">".gettext("Get an OpenID")."</a>" : "")
  32. .')'
  33. );
  34. # Handle submission of an OpenID as validation.
  35. if ($form->submitted && $form->submitted eq "Login" &&
  36. defined $form->field("openid_url") &&
  37. length $form->field("openid_url")) {
  38. $form->field(
  39. name => "openid_url",
  40. validate => sub {
  41. validate($cgi, $session, shift, $form);
  42. },
  43. );
  44. # Skip all other required fields in this case.
  45. foreach my $field ($form->field) {
  46. next if $field eq "openid_url";
  47. $form->field(name => $field, required => 0,
  48. validate => '/.*/');
  49. }
  50. }
  51. }
  52. elsif ($form->title eq "preferences") {
  53. if (! defined $form->field(name => "name")) {
  54. $form->field(name => "OpenID", disabled => 1, value =>
  55. $session->param("name"), size => 30, force => 1);
  56. }
  57. }
  58. }
  59. sub validate ($$$;$) { #{{{
  60. my $q=shift;
  61. my $session=shift;
  62. my $openid_url=shift;
  63. my $form=shift;
  64. my $csr=getobj($q, $session);
  65. my $claimed_identity = $csr->claimed_identity($openid_url);
  66. if (! $claimed_identity) {
  67. if ($form) {
  68. # Put the error in the form and fail validation.
  69. $form->field(name => "openid_url", comment => $csr->err);
  70. return 0;
  71. }
  72. else {
  73. error($csr->err);
  74. }
  75. }
  76. my $check_url = $claimed_identity->check_url(
  77. return_to => IkiWiki::cgiurl(do => "postsignin"),
  78. trust_root => $config{cgiurl},
  79. delayed_return => 1,
  80. );
  81. # Redirect the user to the OpenID server, which will
  82. # eventually bounce them back to auth()
  83. IkiWiki::redirect($q, $check_url);
  84. exit 0;
  85. } #}}}
  86. sub auth ($$) { #{{{
  87. my $q=shift;
  88. my $session=shift;
  89. if (defined $q->param('openid.mode')) {
  90. my $csr=getobj($q, $session);
  91. if (my $setup_url = $csr->user_setup_url) {
  92. IkiWiki::redirect($q, $setup_url);
  93. }
  94. elsif ($csr->user_cancel) {
  95. IkiWiki::redirect($q, $config{url});
  96. }
  97. elsif (my $vident = $csr->verified_identity) {
  98. $session->param(name => $vident->url);
  99. }
  100. else {
  101. error("OpenID failure: ".$csr->err);
  102. }
  103. }
  104. elsif (defined $q->param('openid_identifier')) {
  105. # myopenid.com affiliate support
  106. validate($q, $session, $q->param('openid_identifier'));
  107. }
  108. } #}}}
  109. sub getobj ($$) { #{{{
  110. my $q=shift;
  111. my $session=shift;
  112. eval q{use Net::OpenID::Consumer};
  113. error($@) if $@;
  114. my $ua;
  115. eval q{use LWPx::ParanoidAgent};
  116. if (! $@) {
  117. $ua=LWPx::ParanoidAgent->new;
  118. }
  119. else {
  120. $ua=LWP::UserAgent->new;
  121. }
  122. # Store the secret in the session.
  123. my $secret=$session->param("openid_secret");
  124. if (! defined $secret) {
  125. $secret=$session->param(openid_secret => time);
  126. }
  127. return Net::OpenID::Consumer->new(
  128. ua => $ua,
  129. args => $q,
  130. consumer_secret => $secret,
  131. required_root => $config{cgiurl},
  132. );
  133. } #}}}
  134. 1