forked from lix-project/hydra
* Role-based access control. Only admins can create projects. Only
admins or project owners can edit or delete a project.
This commit is contained in:
parent
161e836d0c
commit
2748cfac07
|
@ -13,6 +13,8 @@ name Hydra
|
|||
<store>
|
||||
class DBIx::Class
|
||||
user_class DB::Users
|
||||
role_relation userroles
|
||||
role_field role
|
||||
</store>
|
||||
</dbic>
|
||||
</realms>
|
||||
|
|
|
@ -11,6 +11,7 @@ use Catalyst qw/-Debug
|
|||
Static::Simple
|
||||
StackTrace
|
||||
Authentication
|
||||
Authorization::Roles
|
||||
Session
|
||||
Session::Store::FastMmap
|
||||
Session::State::Cookie
|
||||
|
|
|
@ -98,7 +98,6 @@ sub requireLogin {
|
|||
|
||||
sub queue :Local {
|
||||
my ($self, $c) = @_;
|
||||
return requireLogin($c) if !$c->user_exists;
|
||||
$c->stash->{template} = 'queue.tt';
|
||||
$c->stash->{queue} = [$c->model('DB::Builds')->search(
|
||||
{finished => 0}, {join => 'schedulingInfo', order_by => ["priority DESC", "timestamp"]})];
|
||||
|
@ -118,6 +117,8 @@ sub updateProject {
|
|||
$project->displayname($displayName);
|
||||
$project->description(trim $c->request->params->{description});
|
||||
$project->enabled(trim($c->request->params->{enabled}) eq "1" ? 1 : 0);
|
||||
$project->owner(trim($c->request->params->{owner}))
|
||||
if $c->check_user_roles('admin');
|
||||
|
||||
$project->update;
|
||||
|
||||
|
@ -236,22 +237,36 @@ sub project :Local {
|
|||
|
||||
$subcommand = "" unless defined $subcommand;
|
||||
|
||||
if ($subcommand ne "") {
|
||||
|
||||
return requireLogin($c) if !$c->user_exists;
|
||||
|
||||
if (!$c->check_user_roles('admin') && $c->user->username ne $project->owner) {
|
||||
return error($c, "Only the project owner or the administrator can perform this operation.");
|
||||
}
|
||||
|
||||
if ($subcommand eq "edit") {
|
||||
$c->stash->{edit} = 1;
|
||||
} elsif ($subcommand eq "submit" && $isPosted) {
|
||||
}
|
||||
|
||||
elsif ($subcommand eq "submit" && $isPosted) {
|
||||
$c->model('DB')->schema->txn_do(sub {
|
||||
updateProject($c, $project);
|
||||
});
|
||||
return $c->res->redirect($c->uri_for("/project", trim $c->request->params->{name}));
|
||||
} elsif ($subcommand eq "delete" && $isPosted) {
|
||||
}
|
||||
|
||||
elsif ($subcommand eq "delete" && $isPosted) {
|
||||
$c->model('DB')->schema->txn_do(sub {
|
||||
$project->delete;
|
||||
});
|
||||
return $c->res->redirect($c->uri_for("/"));
|
||||
} elsif ($subcommand eq "") {
|
||||
} else {
|
||||
}
|
||||
|
||||
else {
|
||||
return error($c, "Unknown subcommand $subcommand.");
|
||||
}
|
||||
}
|
||||
|
||||
$c->stash->{curProject} = $project;
|
||||
|
||||
|
@ -283,6 +298,12 @@ sub project :Local {
|
|||
sub createproject :Local {
|
||||
my ($self, $c, $subcommand) = @_;
|
||||
|
||||
return requireLogin($c) if !$c->user_exists;
|
||||
|
||||
if (!$c->check_user_roles('admin')) {
|
||||
return error($c, "Only administrators can create projects.");
|
||||
}
|
||||
|
||||
if (defined $subcommand && $subcommand eq "submit") {
|
||||
eval {
|
||||
my $projectName = $c->request->params->{name};
|
||||
|
|
|
@ -8,8 +8,8 @@ use base 'DBIx::Class::Schema';
|
|||
__PACKAGE__->load_classes;
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:jK/9VMZBot2RJwtlHA6QIg
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:OcrPIHyQBUa+kF79Ltf95g
|
||||
|
||||
|
||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||
|
|
|
@ -36,8 +36,8 @@ __PACKAGE__->belongs_to("build", "Hydra::Schema::Builds", { id => "build" });
|
|||
__PACKAGE__->belongs_to("dependency", "Hydra::Schema::Builds", { id => "dependency" });
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:LRcAsbLWbetVw+DCDnv/9w
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:BEl4PIMuykTwqyl7La0pKQ
|
||||
|
||||
|
||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||
|
|
|
@ -33,8 +33,8 @@ __PACKAGE__->set_primary_key("build", "productnr");
|
|||
__PACKAGE__->belongs_to("build", "Hydra::Schema::Builds", { id => "build" });
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Pu6gWxltfVJJ+9DBiC9bYg
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:uEkpbb6hgGe47sDE7KtLDQ
|
||||
|
||||
|
||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||
|
|
|
@ -29,8 +29,8 @@ __PACKAGE__->set_primary_key("id");
|
|||
__PACKAGE__->belongs_to("id", "Hydra::Schema::Builds", { id => "id" });
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:X5GXZRLAaCMl8OKBGjtztw
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:CfJnTtjRXGV5dD/MWbrJxA
|
||||
|
||||
|
||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||
|
|
|
@ -70,8 +70,8 @@ __PACKAGE__->has_many(
|
|||
);
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:h32zqOEGcpXQy7pshiWVMA
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:AFGyXbj7hMxpQxjzgpvrCw
|
||||
|
||||
__PACKAGE__->has_many(dependents => 'Hydra::Schema::Buildinputs', 'dependency');
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@ __PACKAGE__->set_primary_key("id");
|
|||
__PACKAGE__->belongs_to("id", "Hydra::Schema::Builds", { id => "id" });
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:egegc7kFKTt9cEGuomi0cQ
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:O6brsCdVF4TfvtmI9R+TOA
|
||||
|
||||
|
||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||
|
|
|
@ -35,8 +35,8 @@ __PACKAGE__->set_primary_key("id", "stepnr");
|
|||
__PACKAGE__->belongs_to("id", "Hydra::Schema::Builds", { id => "id" });
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:kFD90OFRM1aqVVCBCh/geA
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:klPmbTcngdzKN+Dzhj8gvw
|
||||
|
||||
|
||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||
|
|
|
@ -22,8 +22,8 @@ __PACKAGE__->add_columns(
|
|||
__PACKAGE__->set_primary_key("srcpath", "sha256hash");
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:r/3GaLIIWaX1fh8kfuQp+w
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:vGVYmR4k3kezEwiCGSXZWQ
|
||||
|
||||
|
||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||
|
|
|
@ -20,8 +20,8 @@ __PACKAGE__->add_columns(
|
|||
__PACKAGE__->set_primary_key("uri", "revision");
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:yTp1XcBSQ+6OJvVLugRh1w
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ORooKeTpZBPOQCgosHLGeg
|
||||
|
||||
|
||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||
|
|
|
@ -33,8 +33,8 @@ __PACKAGE__->belongs_to(
|
|||
);
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:lYdNLENxLW2mtZ2w+jou8w
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ZeFpiIuYHvaFqRSppuUpoA
|
||||
|
||||
|
||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||
|
|
|
@ -43,8 +43,8 @@ __PACKAGE__->has_many(
|
|||
);
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Bk/vLWpBjR3ZU0p1KN7KfA
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:/PmcpU0eiLZT+dlUZYyTaQ
|
||||
|
||||
|
||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||
|
|
|
@ -50,8 +50,8 @@ __PACKAGE__->has_many(
|
|||
);
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:9xvvQg/H0oibycB6B45V5A
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:EGgAWXbhcEC0uBobJMfpUw
|
||||
|
||||
|
||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||
|
|
|
@ -16,6 +16,8 @@ __PACKAGE__->add_columns(
|
|||
{ data_type => "text", is_nullable => 0, size => undef },
|
||||
"enabled",
|
||||
{ data_type => "integer", is_nullable => 0, size => undef },
|
||||
"owner",
|
||||
{ data_type => "text", is_nullable => 0, size => undef },
|
||||
);
|
||||
__PACKAGE__->set_primary_key("name");
|
||||
__PACKAGE__->has_many(
|
||||
|
@ -30,8 +32,8 @@ __PACKAGE__->has_many(
|
|||
);
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:3YMBhMqCjtpUjoTx4JLTOw
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:jdyfk3vHisJRyE+VNR6dNA
|
||||
|
||||
|
||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||
|
|
|
@ -16,8 +16,8 @@ __PACKAGE__->add_columns(
|
|||
__PACKAGE__->set_primary_key("system");
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:SSKVFeg7ieeLJcF+s1uWWw
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:N/yG0cEhf0Y9Ve9YkdwRfA
|
||||
|
||||
|
||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||
|
|
25
src/Hydra/lib/Hydra/Schema/Userroles.pm
Normal file
25
src/Hydra/lib/Hydra/Schema/Userroles.pm
Normal file
|
@ -0,0 +1,25 @@
|
|||
package Hydra::Schema::Userroles;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use base 'DBIx::Class';
|
||||
|
||||
__PACKAGE__->load_components("Core");
|
||||
__PACKAGE__->table("UserRoles");
|
||||
__PACKAGE__->add_columns(
|
||||
"username",
|
||||
{ data_type => "text", is_nullable => 0, size => undef },
|
||||
"role",
|
||||
{ data_type => "text", is_nullable => 0, size => undef },
|
||||
);
|
||||
__PACKAGE__->set_primary_key("username", "role");
|
||||
__PACKAGE__->belongs_to("username", "Hydra::Schema::Users", { username => "username" });
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:f16iU2I/Htdo7mXHvAdwyQ
|
||||
|
||||
|
||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||
1;
|
|
@ -18,10 +18,15 @@ __PACKAGE__->add_columns(
|
|||
{ data_type => "text", is_nullable => 0, size => undef },
|
||||
);
|
||||
__PACKAGE__->set_primary_key("username");
|
||||
__PACKAGE__->has_many(
|
||||
"userroles",
|
||||
"Hydra::Schema::Userroles",
|
||||
{ "foreign.username" => "self.username" },
|
||||
);
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:BgF6FK+9d7+cc72sp6pfCQ
|
||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:wwRBfogrkKN2QdgmFjcUlA
|
||||
|
||||
|
||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||
|
|
39
src/Hydra/root/login.tt
Normal file
39
src/Hydra/root/login.tt
Normal file
|
@ -0,0 +1,39 @@
|
|||
[% WRAPPER layout.tt title="Login to Hydra" %]
|
||||
[% PROCESS common.tt %]
|
||||
|
||||
<h1>Login</h1>
|
||||
|
||||
[% IF c.user_exists %]
|
||||
<p>
|
||||
You are already logged in as <tt>[% c.user.username %]</tt>.
|
||||
You can <a href="[% c.uri_for('/logout') %]">logout</a> here.
|
||||
</p>
|
||||
[% ELSE %]
|
||||
|
||||
[% IF errorMsg %]
|
||||
<p class="error">Error: [% errorMsg %]</p>
|
||||
[% END %]
|
||||
|
||||
<form method="post" action="[% c.uri_for('/login') %]">
|
||||
|
||||
<table class="layoutTable">
|
||||
<tr>
|
||||
<td>Username:</td>
|
||||
<td><input type="text" name="username" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Password:</td>
|
||||
<td><input type="password" name="password" /></td>
|
||||
</tr>
|
||||
<tr colspan="2">
|
||||
<td>
|
||||
<input type="submit" name="login" value="Login" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</form>
|
||||
|
||||
[% END %]
|
||||
|
||||
[% END %]
|
|
@ -163,6 +163,10 @@
|
|||
<th>Description:</th>
|
||||
<td>[% INCLUDE maybeEditString param="description" value=curProject.description %]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Owner:</th>
|
||||
<td><tt>[% INCLUDE maybeEditString param="owner" value=curProject.owner edit=(edit && c.check_user_roles('admin')) %]</tt></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Enabled:</th>
|
||||
<td>
|
||||
|
|
|
@ -154,6 +154,8 @@ create table Projects (
|
|||
displayName text not null, -- display name (e.g. "PatchELF")
|
||||
description text,
|
||||
enabled integer not null default 1
|
||||
owner text not null,
|
||||
foreign key (owner) references Users(userName) -- ignored by sqlite
|
||||
);
|
||||
|
||||
|
||||
|
@ -269,3 +271,18 @@ create table Users (
|
|||
emailAddress text not null,
|
||||
password text not null -- sha256 hash
|
||||
);
|
||||
|
||||
|
||||
create table UserRoles (
|
||||
userName text not null,
|
||||
role text not null,
|
||||
primary key (userName, role),
|
||||
foreign key (userName) references Users(userName) -- ignored by sqlite
|
||||
);
|
||||
|
||||
|
||||
create trigger cascadeUserDelete
|
||||
before delete on Users
|
||||
for each row begin
|
||||
delete from UserRoles where userName = old.userName;
|
||||
end;
|
||||
|
|
Loading…
Reference in a new issue