Showing 3 changed files with 184 additions and 18 deletions
+50 -14
lib/Gitprep.pm
... ...
@@ -123,6 +123,8 @@ sub startup {
123 123
     }
124 124
   );
125 125
   
126
+  # Basic auth plugin
127
+  $self->plugin('BasicAuth');
126 128
 
127 129
   # Routes
128 130
   sub template {
... ...
@@ -186,20 +188,54 @@ sub startup {
186 188
         {
187 189
           my $r = $r->route('/(:project).git', project => $id_re);
188 190
           
189
-          my $sh = Gitprep::SmartHTTP->new;
190
-          $self->smart_http($sh);
191
-          
192
-          # /info/refs
193
-          $r->get('/info/refs' => template 'smart-http/info-refs');
194
-          
195
-          # /git-upload-pack or /git-receive-pack
196
-          $r->any('/git-(:service)'
197
-            => [service => qr/(?:upload-pack|receive-pack)/]
198
-            => template 'smart-http/service'
199
-          );
200
-          
201
-          # Static file
202
-          $r->get('/(*Path)' => template 'smart-http/static');
191
+          {
192
+            my $r = $r->under(sub {
193
+              my $self = shift;
194
+              
195
+              my $paths = $self->url_for->path->parts;
196
+              
197
+              # Basic auth when push request
198
+              my $service = $self->param('service') || '';
199
+              if ($service eq 'git-receive-pack') {
200
+                
201
+                $self->basic_auth("Git Area", sub {
202
+                  my ($user, $password) = @_;
203
+
204
+                  my $row
205
+                    = $dbi->model('user')->select(['password', 'salt'], id => $user)->one;
206
+                  
207
+                  return unless $row;
208
+                  
209
+                  my $api = $self->gitprep_api;
210
+                  my $is_valid = $api->check_password(
211
+                    $password,
212
+                    $row->{salt},
213
+                    $row->{password}
214
+                  );
215
+                  
216
+                  return $is_valid;
217
+                });
218
+              }
219
+              else {
220
+                return 1;
221
+              }
222
+            });
223
+            
224
+            my $sh = Gitprep::SmartHTTP->new;
225
+            $self->smart_http($sh);
226
+            
227
+            # /info/refs
228
+            $r->get('/info/refs' => template 'smart-http/info-refs');
229
+            
230
+            # /git-upload-pack or /git-receive-pack
231
+            $r->any('/git-(:service)'
232
+              => [service => qr/(?:upload-pack|receive-pack)/]
233
+              => template 'smart-http/service'
234
+            );
235
+            
236
+            # Static file
237
+            $r->get('/(*Path)' => template 'smart-http/static');
238
+          }
203 239
         }
204 240
                 
205 241
         # Project
+127
mojo/lib/Mojolicious/Plugin/BasicAuth.pm
... ...
@@ -0,0 +1,127 @@
1
+package Mojolicious::Plugin::BasicAuth;
2
+
3
+use strict;
4
+use warnings;
5
+use Mojo::ByteStream;
6
+
7
+our $VERSION = '0.07';
8
+
9
+use base 'Mojolicious::Plugin';
10
+
11
+sub register {
12
+    my ($plugin, $app) = @_;
13
+
14
+    $app->renderer->add_helper(
15
+        basic_auth => sub {
16
+            my $self = shift;
17
+
18
+            #
19
+            # Sent Credentials
20
+            my $auth = $self->req->url->to_abs->userinfo || '';
21
+
22
+            # Required credentials
23
+            my ($realm, $password, $username) = $plugin->_expected_auth(@_);
24
+            my $callback = $password if ref $password eq 'CODE';
25
+
26
+            # No credentials entered
27
+            return $plugin->_password_prompt($self, $realm)
28
+              if !$auth and !$callback;
29
+
30
+            # Verification within callback
31
+            return 1 if $callback and $callback->(split /:/, $auth, 2);
32
+
33
+            # Verified with realm => username => password syntax
34
+            return 1 if $auth eq ($username || '') . ":$password";
35
+
36
+            # Not verified
37
+            return $plugin->_password_prompt($self, $realm);
38
+        }
39
+    );
40
+}
41
+
42
+sub _expected_auth {
43
+    my $self  = shift;
44
+    my $realm = shift;
45
+
46
+    return @$realm{qw/ realm password username /} if ref $realm eq "HASH";
47
+
48
+    # realm, pass, user || realm, pass, undef || realm, callback
49
+    return $realm, reverse @_;
50
+}
51
+
52
+sub _password_prompt {
53
+    my ($self, $c, $realm) = @_;
54
+
55
+    $c->res->headers->www_authenticate("Basic realm=$realm");
56
+    $c->res->code(401);
57
+    $c->rendered;
58
+
59
+    return;
60
+}
61
+
62
+1;
63
+__END__
64
+
65
+=head1 NAME
66
+
67
+Mojolicious::Plugin::BasicAuth - Basic HTTP Auth Helper
68
+
69
+=head1 DESCRIPTION
70
+
71
+L<Mojolicous::Plugin::BasicAuth> is a helper for basic http authentication.
72
+
73
+=head1 USAGE
74
+
75
+    use Mojolicious::Lite;
76
+
77
+    plugin 'basic_auth';
78
+
79
+    get '/' => sub {
80
+        my $self = shift;
81
+
82
+        return $self->render_text('ok')
83
+          if $self->basic_auth(
84
+                  realm => sub { return 1 if "@_" eq 'username password' }
85
+          );
86
+    };
87
+
88
+    app->start;
89
+
90
+=head1 METHODS
91
+
92
+L<Mojolicious::Plugin::BasicAuth> inherits all methods from
93
+L<Mojolicious::Plugin> and implements the following new ones.
94
+
95
+=head2 C<register>
96
+
97
+    $plugin->register;
98
+
99
+Register condition in L<Mojolicious> application.
100
+
101
+=head1 SEE ALSO
102
+
103
+L<Mojolicious>
104
+
105
+=head1 DEVELOPMENT
106
+
107
+L<http://github.com/tempire/mojolicious-plugin-basicauth>
108
+
109
+=head1 VERSION
110
+
111
+0.07
112
+
113
+=head1 CREDITS
114
+
115
+=over 4
116
+
117
+=item Kirill Miazine
118
+
119
+=item reneeb
120
+
121
+=back
122
+
123
+=head1 AUTHOR
124
+
125
+Glen Hinkle tempire@cpan.org
126
+
127
+=cut
+7 -4
templates/smart-http/info-refs.html.ep
... ...
@@ -10,10 +10,13 @@
10 10
   my $sh = app->smart_http;
11 11
   
12 12
   # Smart HTTP
13
-  if ($service eq 'git-upload-pack') {
13
+  if ($service eq 'git-upload-pack' || $service eq 'git-receive-pack') {
14
+    
15
+    my $service_cmd = $service;
16
+    substr($service_cmd, 0, 4, '');
14 17
     
15 18
     my $rep = $git->rep($user, $project);
16
-    my @cmd = $git->cmd($user, $project, 'upload-pack', '--stateless-rpc', '--advertise-refs', $rep);
19
+    my @cmd = $git->cmd($user, $project, $service_cmd, '--stateless-rpc', '--advertise-refs', $rep);
17 20
     
18 21
     my ($cout, $cerr) = (Symbol::gensym, Symbol::gensym);
19 22
     my $pid = IPC::Open3::open3(my $cin, $cout, $cerr, @cmd );
... ...
@@ -44,10 +47,10 @@
44 47
       return;
45 48
     }
46 49
     
47
-    $self->res->headers->content_type('application/x-git-upload-pack-advertisement');
50
+    $self->res->headers->content_type("application/x-$service-advertisement");
48 51
     
49 52
     # Data start
50
-    my $message = "# service=git-upload-pack\n";
53
+    my $message = "# service=$service\n";
51 54
     my $data = sprintf( '%04x', length($message) + 4 ) . $message . '0000' . $refs;
52 55
     
53 56
     $self->render(data => $data);