... | ... |
@@ -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 |
... | ... |
@@ -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 |
... | ... |
@@ -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); |