summaryrefslogtreecommitdiff
path: root/IkiWiki/Plugin/openid.pm
blob: 8bf3f63fd3048e568ad572ac59e613860937d077 (plain)
  1. #!/usr/bin/perl
  2. # OpenID support.
  3. package IkiWiki::Plugin::openid;
  4. use warnings;
  5. use strict;
  6. use IkiWiki 2.00;
  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", noimageinline => 1, linktext => 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,
  55. value => $session->param("name"),
  56. size => 50, force => 1,
  57. fieldset => "login");
  58. }
  59. }
  60. }
  61. sub validate ($$$;$) { #{{{
  62. my $q=shift;
  63. my $session=shift;
  64. my $openid_url=shift;
  65. my $form=shift;
  66. my $csr=getobj($q, $session);
  67. my $claimed_identity = $csr->claimed_identity($openid_url);
  68. if (! $claimed_identity) {
  69. if ($form) {
  70. # Put the error in the form and fail validation.
  71. $form->field(name => "openid_url", comment => $csr->err);
  72. return 0;
  73. }
  74. else {
  75. error($csr->err);
  76. }
  77. }
  78. my $check_url = $claimed_identity->check_url(
  79. return_to => IkiWiki::cgiurl(do => "postsignin"),
  80. trust_root => $config{cgiurl},
  81. delayed_return => 1,
  82. );
  83. # Redirect the user to the OpenID server, which will
  84. # eventually bounce them back to auth()
  85. IkiWiki::redirect($q, $check_url);
  86. exit 0;
  87. } #}}}
  88. sub auth ($$) { #{{{
  89. my $q=shift;
  90. my $session=shift;
  91. if (defined $q->param('openid.mode')) {
  92. my $csr=getobj($q, $session);
  93. if (my $setup_url = $csr->user_setup_url) {
  94. IkiWiki::redirect($q, $setup_url);
  95. }
  96. elsif ($csr->user_cancel) {
  97. IkiWiki::redirect($q, $config{url});
  98. }
  99. elsif (my $vident = $csr->verified_identity) {
  100. $session->param(name => $vident->url);
  101. }
  102. else {
  103. error("OpenID failure: ".$csr->err);
  104. }
  105. }
  106. elsif (defined $q->param('openid_identifier')) {
  107. # myopenid.com affiliate support
  108. validate($q, $session, $q->param('openid_identifier'));
  109. }
  110. } #}}}
  111. sub getobj ($$) { #{{{
  112. my $q=shift;
  113. my $session=shift;
  114. eval q{use Net::OpenID::Consumer};
  115. error($@) if $@;
  116. my $ua;
  117. eval q{use LWPx::ParanoidAgent};
  118. if (! $@) {
  119. $ua=LWPx::ParanoidAgent->new;
  120. }
  121. else {
  122. $ua=LWP::UserAgent->new;
  123. }
  124. # Store the secret in the session.
  125. my $secret=$session->param("openid_secret");
  126. if (! defined $secret) {
  127. $secret=rand;
  128. $session->param(openid_secret => $secret);
  129. }
  130. return Net::OpenID::Consumer->new(
  131. ua => $ua,
  132. args => $q,
  133. consumer_secret => sub { return shift()+$secret },
  134. required_root => $config{cgiurl},
  135. );
  136. } #}}}
  137. 1