summaryrefslogtreecommitdiff
path: root/IkiWiki/Plugin/openid.pm
blob: fcd53ee71c4973ffafc0f2a9e6871fed997eb97c (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. # This avoids it displaying a redundant label for the
  26. # OpenID fieldset.
  27. $form->fieldsets("OpenID");
  28. $form->field(
  29. name => "openid_url",
  30. label => gettext("Log in with")." ".htmllink("", "", "OpenID", noimageinline => 1),
  31. fieldset => "OpenID",
  32. size => 30,
  33. comment => ($config{openidsignup} ? " | <a href=\"$config{openidsignup}\">".gettext("Get an OpenID")."</a>" : "")
  34. );
  35. # Handle submission of an OpenID as validation.
  36. if ($form->submitted && $form->submitted eq "Login" &&
  37. defined $form->field("openid_url") &&
  38. length $form->field("openid_url")) {
  39. $form->field(
  40. name => "openid_url",
  41. validate => sub {
  42. validate($cgi, $session, shift, $form);
  43. },
  44. );
  45. # Skip all other required fields in this case.
  46. foreach my $field ($form->field) {
  47. next if $field eq "openid_url";
  48. $form->field(name => $field, required => 0,
  49. validate => '/.*/');
  50. }
  51. }
  52. }
  53. elsif ($form->title eq "preferences") {
  54. if (! defined $form->field(name => "name")) {
  55. $form->field(name => "OpenID", disabled => 1,
  56. value => $session->param("name"),
  57. size => 50, force => 1,
  58. fieldset => "login");
  59. }
  60. }
  61. }
  62. sub validate ($$$;$) { #{{{
  63. my $q=shift;
  64. my $session=shift;
  65. my $openid_url=shift;
  66. my $form=shift;
  67. my $csr=getobj($q, $session);
  68. my $claimed_identity = $csr->claimed_identity($openid_url);
  69. if (! $claimed_identity) {
  70. if ($form) {
  71. # Put the error in the form and fail validation.
  72. $form->field(name => "openid_url", comment => $csr->err);
  73. return 0;
  74. }
  75. else {
  76. error($csr->err);
  77. }
  78. }
  79. my $check_url = $claimed_identity->check_url(
  80. return_to => IkiWiki::cgiurl(do => "postsignin"),
  81. trust_root => $config{cgiurl},
  82. delayed_return => 1,
  83. );
  84. # Redirect the user to the OpenID server, which will
  85. # eventually bounce them back to auth()
  86. IkiWiki::redirect($q, $check_url);
  87. exit 0;
  88. } #}}}
  89. sub auth ($$) { #{{{
  90. my $q=shift;
  91. my $session=shift;
  92. if (defined $q->param('openid.mode')) {
  93. my $csr=getobj($q, $session);
  94. if (my $setup_url = $csr->user_setup_url) {
  95. IkiWiki::redirect($q, $setup_url);
  96. }
  97. elsif ($csr->user_cancel) {
  98. IkiWiki::redirect($q, $config{url});
  99. }
  100. elsif (my $vident = $csr->verified_identity) {
  101. $session->param(name => $vident->url);
  102. }
  103. else {
  104. error("OpenID failure: ".$csr->err);
  105. }
  106. }
  107. elsif (defined $q->param('openid_identifier')) {
  108. # myopenid.com affiliate support
  109. validate($q, $session, $q->param('openid_identifier'));
  110. }
  111. } #}}}
  112. sub getobj ($$) { #{{{
  113. my $q=shift;
  114. my $session=shift;
  115. eval q{use Net::OpenID::Consumer};
  116. error($@) if $@;
  117. my $ua;
  118. eval q{use LWPx::ParanoidAgent};
  119. if (! $@) {
  120. $ua=LWPx::ParanoidAgent->new;
  121. }
  122. else {
  123. $ua=LWP::UserAgent->new;
  124. }
  125. # Store the secret in the session.
  126. my $secret=$session->param("openid_secret");
  127. if (! defined $secret) {
  128. $secret=rand;
  129. $session->param(openid_secret => $secret);
  130. }
  131. return Net::OpenID::Consumer->new(
  132. ua => $ua,
  133. args => $q,
  134. consumer_secret => sub { return shift()+$secret },
  135. required_root => $config{cgiurl},
  136. );
  137. } #}}}
  138. 1