App-LDAP

 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;



( run in 1.313 second using v1.01-cache-2.11-cpan-5735350b133 )