view release on metacpan or search on metacpan
lib/App/LDAP/Command/Add/Group.pm view on Meta::CPAN
is => "rw",
isa => "ArrayRef[Str]",
);
use App::LDAP::LDIF::Group;
# {{{
sub run {
my ($self) = shift;
my $gid = next_gid();
my $groupname = $self->extra_argv->[2] or die "no group name specified";
die "group $groupname already exists" if App::LDAP::LDIF::Group->search(
base => config()->{nss_base_group}->[0],
scope => config()->{nss_base_group}->[1],
filter => "cn=$groupname",
);
my $group = App::LDAP::LDIF::Group->new(
base => $self->base // config()->{nss_base_group}->[0],
cn => [$groupname],
gidNumber => $gid->get_value("gidNumber"),
);
$group->memberUid( $self->member ) if $self->member;
$group->save;
$gid->replace(gidNumber => $gid->get_value("gidNumber")+1)->update(ldap());
$group;
}
# }}}
sub next_gid {
ldap()->search(
base => config()->{base},
filter => "(objectClass=gidnext)",
)->entry(0);
}
__PACKAGE__->meta->make_immutable;
no Moose;
1;
lib/App/LDAP/Command/Add/User.pm view on Meta::CPAN
base => config()->{nss_base_passwd}->[0],
scope => config()->{nss_base_passwd}->[1],
filter => "uid=$username",
);
my $user = App::LDAP::LDIF::User->new(
base => $self->base // config()->{nss_base_passwd}->[0],
uid => $username,
userPassword => encrypt(new_password()),
uidNumber => $uid->get_value("uidNumber"),
gidNumber => $self->gid_of( $self->group ),
sn => $self->surname,
mail => $self->mail,
);
$user->loginShell ( $self->shell ) if $self->shell;
$user->homeDirectory ( $self->home ) if $self->home;
$user->save;
$uid->replace(uidNumber => $uid->get_value("uidNumber")+1)->update(ldap());
lib/App/LDAP/Command/Add/User.pm view on Meta::CPAN
}
# }}}
sub next_uid {
ldap()->search(
base => config()->{base},
filter => "(objectClass=uidnext)",
)->entry(0);
}
sub gid_of {
my ($self, $groupname) = @_;
use App::LDAP::LDIF::Group;
my $group = App::LDAP::LDIF::Group->search(
base => config()->{nss_base_group}->[0],
scope => config()->{nss_base_group}->[1],
filter => "cn=$groupname",
);
return $group ? $group->gidNumber : $self->create_group($groupname)->gidNumber;
}
sub create_group {
my ($self, $groupname) = @_;
use App::LDAP::Command::Add::Group;
local *ARGV = ['add', 'group', $groupname];
App::LDAP::Command::Add::Group->new_with_options->run;
}
lib/App/LDAP/Command/Del/User.pm view on Meta::CPAN
$self->delete_group_of_user($user);
$user->delete;
}
sub delete_group_of_user {
my ($self, $user) = @_;
my $cn = $user->uid;
my $gidNumber = $user->gidNumber;
use App::LDAP::LDIF::Group;
my $group = App::LDAP::LDIF::Group->search(
base => config()->{nss_base_group}->[0],
scope => config()->{nss_base_group}->[1],
filter => "(& (gidNumber=$gidNumber) (cn=$cn))",
);
$group->delete if $group;
}
__PACKAGE__->meta->make_immutable;
no Moose;
1;
lib/App/LDAP/Command/Init.pm view on Meta::CPAN
$ldap->bind(undef, sasl => $sasl);
for my $schema (keys %{$schemas}) {
my $file = IO::String->new($schemas->{$schema});
my $entry = Net::LDAP::LDIF->new($file, "r", onerror => "die")->read_entry();
my $msg = $ldap->add($entry);
die $msg->error if $msg->code;
}
ldap()->add($self->create_gidnext);
ldap()->add($self->create_uidnext);
}
$schemas->{idnext} = <<'IDNEXT';
dn: cn=idnext,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: idnext
olcObjectClasses: {0}( 1.3.6.1.4.1.7165.1.2.2.3
NAME 'uidNext' SUP top STRUCTURAL
DESC 'Next available UNIX uid'
MUST ( uidNumber $ cn ) )
olcObjectClasses: {1}( 1.3.6.1.4.1.7165.1.2.2.4
NAME 'gidNext' SUP top STRUCTURAL
DESC 'Next available UNIX gid'
MUST ( gidNumber $ cn ) )
IDNEXT
$schemas->{sudo} = <<'SUDO';
dn: cn=sudo,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: sudo
olcAttributeTypes: {0}( 1.3.6.1.4.1.15953.9.1.1 NAME 'sudoUser' DESC 'User(s)
who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMa
tch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: {1}( 1.3.6.1.4.1.15953.9.1.2 NAME 'sudoHost' DESC 'Host(s)
lib/App/LDAP/Command/Init.pm view on Meta::CPAN
my $base = config()->{base};
my $uidnext = Net::LDAP::Entry->new("cn=uidnext,$base");
$uidnext->add(
cn => "uidnext",
objectClass => "uidNext",
uidNumber => 1001,
);
return $uidnext;
}
sub create_gidnext {
my ($self, ) = @_;
my $base = config()->{base};
my $gidnext = Net::LDAP::Entry->new("cn=gidnext,$base");
$gidnext->add(
cn => "gidnext",
objectClass => "gidNext",
gidNumber => 1001,
);
return $gidnext;
}
__PACKAGE__->meta->make_immutable;
no Moose;
1;
=pod
=head1 NAME
lib/App/LDAP/Command/Init.pm view on Meta::CPAN
=head1 DESCRIPTION
This command initailizes the environment of LDAP server for App::LDAP to function.
1. import the schema of idnext
2. import the schema of sudo
3. add a entry of uidnext, uidNumber 1001
4. add a entry of gidnext, gidNumber 1001
=cut
lib/App/LDAP/LDIF/Group.pm view on Meta::CPAN
=head1 NAME
App::LDAP::LDIF::Group - the representation of groups in LDAP
=head1 SYNOPSIS
my $group = App::LDAP::LDIF::Group->new(
base => $base, # The OU (organization unit) which the group belongs to
cn => [$name], # the group name
gidNumber => $id, # the gid of the group
);
# these three attributes are required
my $entry = $group->entry;
# get the group as a instance of Net::LDAP::Entry
my $group = App::LDAP::LDIF::Group->new($entry)
# new from a entry
=cut
lib/App/LDAP/LDIF/User.pm view on Meta::CPAN
App::LDAP::LDIF::User - the representation of users in LDAP
=head1 SYNOPSIS
my $user = App::LDAP::LDIF::User->new(
base => $base, # the OU (organization unit) which the user belongs to
uid => $name, # user name
userPassword => $password, # the password used by the user
uidNumber => $uid, # the uid of the user
gidNumber => $gid, # the gid of the user
sn => [$sn], # the surname of this user
);
# these 6 parameters are required
# extra parameters of attributes such as title of User can be provided in constructor, too.
$user->loginShell("/bin/zsh")
# set zsh as the user's shell
$uesr->gidNumber("27")
# set the user to have 27 as group id
my $entry = $user->entry
# get the user as a instance of Net::LDAP::Entry
my $from_entry = App::LDAP::LDIF::User->new($entry)
# new from a Net::LDAP::Entry instance
=head1 DESCRIPTION
lib/App/LDAP/ObjectClass/PosixAccount.pm view on Meta::CPAN
use Moose;
extends qw(App::LDAP::ObjectClass::Top);
has cn => (
is => "rw",
isa => "ArrayRef[Str]",
required => 1,
);
has [qw(uid uidNumber gidNumber homeDirectory)] => (
is => "rw",
isa => "Str",
required => 1,
);
has [qw(userPassword loginShell gecos description)] => (
is => "rw",
isa => "Str",
);
lib/App/LDAP/ObjectClass/PosixAccount.pm view on Meta::CPAN
App::LDAP::ObjectClass::PosixAccount - schema of posixAccount
=head1 DEFINITION
objectclass (
1.3.6.1.1.1.2.0
NAME 'posixAccount'
DESC 'Abstraction of an account with POSIX attributes'
SUP top
AUXILIARY
MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
MAY ( userPassword $ loginShell $ gecos $ description )
)
=cut
lib/App/LDAP/ObjectClass/PosixGroup.pm view on Meta::CPAN
use Moose;
extends qw(App::LDAP::ObjectClass::Top);
has cn => (
is => "rw",
isa => "ArrayRef[Str]",
required => 1,
);
has gidNumber => (
is => "rw",
isa => "Str",
required => 1,
);
has [qw(userPassword description)] => (
is => "rw",
isa => "Str",
);
lib/App/LDAP/ObjectClass/PosixGroup.pm view on Meta::CPAN
App::LDAP::ObjectClass::PosixGroup - schema of posixGroup
=head1 DEFINITION
objectclass (
1.3.6.1.1.1.2.2
NAME 'posixGroup'
DESC 'Abstraction of a group of accounts'
SUP top
STRUCTURAL
MUST ( cn $ gidNumber )
MAY ( userPassword $ memberUid $ description )
)
=cut
schema/cn=idnext.ldif view on Meta::CPAN
dn: cn=idnext,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: idnext
olcObjectClasses: {0}( 1.3.6.1.4.1.7165.1.2.2.3
NAME 'uidNext' SUP top STRUCTURAL
DESC 'Next available UNIX uid'
MUST ( uidNumber $ cn ) )
olcObjectClasses: {1}( 1.3.6.1.4.1.7165.1.2.2.4
NAME 'gidNext' SUP top STRUCTURAL
DESC 'Next available UNIX gid'
MUST ( gidNumber $ cn ) )
t/ldif/group.t view on Meta::CPAN
use Modern::Perl;
use Test::More;
BEGIN {
use_ok 'App::LDAP::LDIF::Group';
}
my $group = App::LDAP::LDIF::Group->new(
base => "ou=Group,dc=example,dc=com",
cn => ["nobody", "unknown"],
gidNumber => 1001,
memberUid => [qw(foo bar)],
description => "this is a nobody group",
);
is_deeply (
[sort map {$_->name} App::LDAP::LDIF::Group->meta->get_all_attributes],
[sort qw( dn
objectClass
cn
gidNumber
userPassword
memberUid
description )],
"make sure attributes",
);
is_deeply (
[sort map {
$_->name
} grep {
$_->is_required
} App::LDAP::LDIF::Group->meta->get_all_attributes],
[sort qw( dn
objectClass
cn
gidNumber )],
"make sure required attributes",
);
is (
$group->dn,
"cn=nobody,ou=Group,dc=example,dc=com",
"dn is compose of first cn and ou",
);
is_deeply (
t/ldif/group.t view on Meta::CPAN
"cn is correct",
);
is (
$group->userPassword,
"{crypt}x",
"userPassword has default value",
);
is (
$group->gidNumber,
"1001",
"gidNumber is correct",
);
is_deeply (
$group->memberUid,
[qw(foo bar)],
"memberUid is correct",
);
is (
$group->description,
t/ldif/group.t view on Meta::CPAN
);
like (
$group->entry->ldif,
qr{userPassword: {crypt}x},
"userPassword has been exported",
);
like (
$group->entry->ldif,
qr{gidNumber: 1001},
"gidNumber has been exported",
);
like (
$group->entry->ldif,
qr{
memberUid: foo
memberUid: bar
},
"memberUid has been exported",
);
t/ldif/group.t view on Meta::CPAN
);
use IO::String;
my $ldif_string = IO::String->new(q{
dn: cn=foo,ou=Group,dc=example,dc=com
objectClass: posixGroup
objectClass: top
cn: foo
userPassword: {crypt}x
gidNumber: 2000
memberUid: foo
memberUid: bar
description: this is a foo group
});
my $entry = Net::LDAP::LDIF->new($ldif_string, "r", onerror => "die")->read_entry;
my $new_from_entry = App::LDAP::LDIF::Group->new($entry);
is (
t/ldif/group.t view on Meta::CPAN
"cn is read",
);
is (
$new_from_entry->userPassword,
"{crypt}x",
"userPassword is read",
);
is (
$new_from_entry->gidNumber,
"2000",
"gidNumber is read",
);
is_deeply (
$new_from_entry->memberUid,
[qw(foo bar)],
"memberUid is read",
);
is (
$new_from_entry->description,
t/ldif/user.t view on Meta::CPAN
BEGIN {
use_ok 'App::LDAP::LDIF::User';
}
my $user = App::LDAP::LDIF::User->new(
base => "ou=People,dc=example,dc=com",
uid => "nobody",
userPassword => "appldap0000",
uidNumber => 1001,
gidNumber => 1001,
sn => ["nobody"],
mail => ['nobody@example.com'],
title => "Engineer",
);
is_deeply (
[sort map {$_->name} App::LDAP::LDIF::User->meta->get_all_attributes],
[sort qw( dn
uid
cn
t/ldif/user.t view on Meta::CPAN
userPassword
shadowLastChange
shadowMin
shadowMax
shadowWarning
shadowInactive
shadowExpire
shadowFlag
loginShell
uidNumber
gidNumber
gecos
description
homeDirectory
sn
mail
audio
businessCategory
carLicense
departmentNumber
t/ldif/user.t view on Meta::CPAN
"ensure the attributes",
);
is_deeply (
[sort map { $_->name } grep { $_->is_required } App::LDAP::LDIF::User->meta->get_all_attributes],
[sort qw( objectClass
sn
cn
uid
uidNumber
gidNumber
homeDirectory
dn
userPassword )],
"make sure required attributes",
);
is (
$user->dn,
"uid=nobody,ou=People,dc=example,dc=com",
t/ldif/user.t view on Meta::CPAN
);
like (
$user->entry->ldif,
qr{uidNumber: 1001},
"uidNumber has been exported",
);
like (
$user->entry->ldif,
qr{gidNumber: 1001},
"gidNumber has been exported",
);
like (
$user->entry->ldif,
qr{title: Engineer},
"title has been exported",
);
use IO::String;
t/ldif/user.t view on Meta::CPAN
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
userPassword: {crypt}$6$PqFBTKAN$H9of7E7oITubjIQqWNIs3YrVkjVGgiUBzhWRc9G6EHvC1
VqVyHOJvf7nRoYeyCCVprZpH4otVQAHcxowOAmD91
shadowLastChange: 22222
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/bash
uidNumber: 2000
gidNumber: 2000
homeDirectory: /home/foo
title: Engineer
});
my $entry = Net::LDAP::LDIF->new($ldif_string, "r", onerror => "die")->read_entry;
my $new_from_entry = App::LDAP::LDIF::User->new($entry);
is_deeply (
$new_from_entry->objectClass,
t/ldif/user.t view on Meta::CPAN
"new from entry has the same objectClasses",
);
is (
$new_from_entry->uidNumber,
2000,
"uidNumber is correct",
);
is (
$new_from_entry->gidNumber,
2000,
"gidNumber is correct",
);
is_deeply (
$new_from_entry->sn,
["foo"],
"sn is correct",
);
is_deeply (
$new_from_entry->mail,
t/objectclass/posixaccount.t view on Meta::CPAN
BEGIN {
use_ok 'App::LDAP::ObjectClass::PosixAccount';
}
is_deeply (
[sort map {$_->name} App::LDAP::ObjectClass::PosixAccount->meta->get_all_attributes],
[sort qw( objectClass
cn
uid
uidNumber
gidNumber
homeDirectory
userPassword
loginShell
gecos
description )],
"make sure attributes",
);
is_deeply (
[sort map {
$_->name
} grep {
$_->is_required
} App::LDAP::ObjectClass::PosixAccount->meta->get_all_attributes],
[sort qw( objectClass cn uid uidNumber gidNumber homeDirectory )],
"make sure required attributes",
);
my %params = (
objectClass => ['posixAccount'],
cn => ["foo"],
uid => "foo",
uidNumber => "2000",
gidNumber => "2000",
homeDirectory => "/home/foo",
);
lives_ok (
sub { App::LDAP::ObjectClass::PosixAccount->new(%params) },
"should live if providing all required parameters",
);
for (qw( objectClass cn uid uidNumber gidNumber homeDirectory )) {
my %p = %params;
delete $p{$_};
dies_ok (
sub { App::LDAP::ObjectClass::PosixAccount->new(%p) },
"should die if no $_",
);
}
ok (
t/objectclass/posixgroup.t view on Meta::CPAN
use Test::Exception;
BEGIN {
use_ok 'App::LDAP::ObjectClass::PosixGroup';
}
is_deeply (
[sort map {$_->name} App::LDAP::ObjectClass::PosixGroup->meta->get_all_attributes],
[sort qw( objectClass
cn
gidNumber
userPassword
memberUid
description )],
"make sure attributes",
);
is_deeply (
[sort map {
$_->name
} grep {
$_->is_required
} App::LDAP::ObjectClass::PosixGroup->meta->get_all_attributes],
[sort qw( objectClass cn gidNumber )],
"make sure required attributes",
);
ok (
App::LDAP::ObjectClass::PosixGroup->DOES("App::LDAP::ObjectClass::Top"),
"posixGroup DOES/SUP top"
);
done_testing;