File Coverage

blib/lib/Dancer/Plugin/Auth/Github.pm
Criterion Covered Total %
statement 27 52 51.9
branch 0 10 0.0
condition n/a
subroutine 9 12 75.0
pod 0 1 0.0
total 36 75 48.0


line stmt bran cond sub pod time code
1             package Dancer::Plugin::Auth::Github;
2              
3 1     1   36581 use Dancer ':syntax';
  1         355465  
  1         5  
4 1     1   1145 use Dancer::Plugin;
  1         1144  
  1         65  
5              
6 1     1   62 use 5.006;
  1         10  
  1         37  
7 1     1   5 use strict;
  1         2  
  1         30  
8 1     1   5 use warnings FATAL => 'all';
  1         1  
  1         37  
9 1     1   4 use Carp 'croak';
  1         2  
  1         45  
10              
11 1     1   3430 use Digest::SHA qw(sha256_hex);
  1         5335  
  1         133  
12 1     1   1401 use LWP::UserAgent;
  1         23256  
  1         41  
13 1     1   1268 use JSON qw(decode_json);
  1         16603  
  1         7  
14              
15              
16             our $VERSION = '0.04';
17              
18             my $client_id;
19             my $client_secret;
20             my $scope = "";
21             my $github_redirect_url = 'https://github.com/login/oauth/authorize/';
22             my $github_post_url = 'https://github.com/login/oauth/access_token/';
23             my $github_auth_failed = '/auth/github/failed';
24             my $github_auth_success = '/';
25             my $state_salt = "RandomSalt";
26              
27             #A method to initializa everything
28             register 'auth_github_init' => sub {
29 0     0     my $config = plugin_setting;
30            
31 0           $client_id = $config->{client_id};
32 0           $client_secret = $config->{client_secret};
33            
34 0           for my $param (qw/client_id client_secret/) {
35 0 0         croak "'$param' is expected but not found in configuration"
36             unless $config->{$param};
37             }
38             #sthe following configs are optional.
39 0 0         if($config->{scope}) {
40 0           $scope = $config->{scope};
41             }
42             #these configs have default values.
43 0 0         if($config->{github_auth_failed})
44             {
45 0           $github_auth_failed = $config->{github_auth_failed};
46             }
47 0 0         if($config->{github_auth_success})
48             {
49 0           $github_auth_success = $config->{github_auth_success};
50             }
51 0           debug 'Loaded config..';
52             };
53             #returns the url you need to redirect to to authenticate on github
54             register 'auth_github_authenticate_url' => sub {
55 0     0     my $generate_state = sha256_hex($client_id.$client_secret.$state_salt);
56 0           return "$github_redirect_url?&client_id=$client_id&scope=$scope&state=$generate_state";
57             };
58             #registers this as a callback url
59             get '/auth/github/callback' => sub {
60             my $generate_state = sha256_hex($client_id.$client_secret.$state_salt);
61             my $state_received = params->{'state'};
62             if($state_received eq $generate_state) {
63             my $code = params->{'code'};
64             my $browser = LWP::UserAgent->new;
65             my $resp = $browser->post($github_post_url,
66             [
67             client_id => $client_id,
68             client_secret => $client_secret,
69             code => $code,
70             state => $state_received
71             ]);
72             die "error while fetching: ", $resp->status_line
73             unless $resp->is_success;
74            
75             my %querystr = parse_query_str($resp->decoded_content);
76             my $acc = $querystr{access_token};
77            
78             if($acc) {
79             my $jresp = $browser->get("https://api.github.com/user?access_token=$acc");
80             my $json = decode_json($jresp->decoded_content);
81             session 'github_user' => $json;
82             session 'github_access_token' => $acc;
83             #session 'logged_in' => true;
84             redirect $github_auth_success;
85             return;
86             }
87             }
88             redirect $github_auth_failed;
89             };
90              
91             #helper method to parse query string.
92             sub parse_query_str {
93 0     0 0   my $str = shift;
94 0           my %in = ();
95 0 0         if (length ($str) > 0){
96 0           my $buffer = $str;
97 0           my @pairs = split(/&/, $buffer);
98 0           foreach my $pair (@pairs){
99 0           my ($name, $value) = split(/=/, $pair);
100 0           $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
  0            
101 0           $in{$name} = $value;
102             }
103             }
104 0           return %in;
105             }
106             register_plugin;
107              
108             1; # End of Dancer::Plugin::Auth::Github
109             __END__