MojoX-Authentication

 view release on metacpan or  search on metacpan

lib/MojoX/Authentication.pm  view on Meta::CPAN

};

sub app_startup ($self, $app = undef) {
   $self->_set_app($app) if defined($app);
   $app = $self->app;
   my $authn = $self->model;

   # add Mojolicious::Plugin::Authentication with the "right" callbacks
   $app->plugin( Authentication => {
      load_user     => sub (@args) { $authn->load_user(@args)     },
      validate_user => sub (@args) { $authn->validate_user(@args) },
   });

   # set a hook to set the user's data in the stash, associated to the
   # requested user_stash_key. This stash key is always set anyway, to
   # avoid errors in the templates in case it's missing
   my $key = $self->user_stash_key;
   $app->hook(
      before_render => sub ($c, $args) {
         my $user = $c->is_user_authenticated ? $c->current_user : undef;
         $c->stash($key => $user);

lib/MojoX/Authentication.pm  view on Meta::CPAN

      (my $saml_id = $c->signed_cookie('saml-id'))
         or ouch 400, 'Not expecting anything SAML-related', 'no id';
      defined(my $saml_response = $c->param('SAMLResponse'))
         or ouch 400, 'No SAMLResponse';

      my $saml2 = $self->_get_provider($c);
      my $user = $saml2->parse_assertion($saml_id, $saml_response);
      my $uid = $user->{$saml2->user_key};

      # we're not using credentials here, so "username" and "password" do
      # not make sense. We use "auto_validate" instead and skip
      # validate_user altogether
      $c->authenticate(undef, undef, { auto_validate => $uid });
      $c->log->info("login successful (SAML2): $uid");
      $c->flash(message => [ info => "Welcome, $user->{fullname}" ]);
      $c->redirect_to($self->_route_for($route_for, 'ok'));
   }
   catch {
      my $message = bleep() || 'Error: invalid credentials';
      $message .= ' ' . Dumper($_->data) if eval { $_->isa('Ouch') };
      $c->log->error('authentication error (SAML2): ' . $message);
      $c->flash(message => [ error => 'Authentication error' ]);
      $c->redirect_to($self->_route_for($route_for, 'not_ok'));

lib/MojoX/Authentication/Model.pm  view on Meta::CPAN


sub load_user ($self, $app, $uid) {
   my ($user, $provider_name) = $self->_iterate(undef, $app, $uid);
   return {
      provider => $provider_name,
      uid      => $uid,
      data     => $user,
   };
}

sub validate_user ($self, $ctr, $username, $secret, $extra) {
   my ($uid) = $self->_iterate(undef, $ctr, $username, $secret, $extra);
   return $uid if defined($uid);
   return;
}

1;

lib/MojoX/Authentication/Model.pod  view on Meta::CPAN

         },
      ],
   );

   my $provider = $am->provider_named('local-db');

   # mostly used with Mojolicious::Plugin::Authentication
   $app->plugin(Authentication => {
      ...
      load_user     => sub (@args) { $am->load_user(@args)     },
      validate_user => sub (@args) { $am->validate_user(@args) },
   });

=head1 DESCRIPTION

This module provides a model that acts as an entry point for several
competing <identity providers> of different nature.

As an example, you might want to support holding users in a hash
(possibly configured in a development environment) as well as in a
database or externally in a SAML 2.0 identity provider. This module lets

lib/MojoX/Authentication/Model.pod  view on Meta::CPAN

         {
            class => 'MojoX::Authentication::Model::SAML2',
            name => 'external-idp',
            args => { ... },
         },
      ],
   );
   $app->plugin(Authentication => {
      ...
      load_user     => sub (@args) { $am->load_user(@args)     },
      validate_user => sub (@args) { $am->validate_user(@args) },
   });

The constructor for this module is fed with three providers.

The first one takes a definition from a reference with hardcoded
values and cleartext passwords, which is of course B<NOT> secure at all.
Anyway, we only use C<$development_users> if the environment variable
C<DEVEL> is true, otherwise it's the empty array to win. This means that
in the development environment we get users C<foo> and C<bar> with their
simple password, while elsewhere we don't get them (at least not from

lib/MojoX/Authentication/Model.pod  view on Meta::CPAN



=head3 B<< provider_name_for >>

   my $name = $am->provider_name_for($controller, $username);

Retrieve the name of the provider that is capable of handling the user
identified by C<$username>.


=head3 B<< validate_user >>

   my $uid = $am->validate_user($controller, $username, $secret, $extra);

Perform validation of credentials for C<$username>.

The interface is compatible with L<Mojolicious::Plugin::Authentication>
like this:

   my $am = ...;
   $app->plugin(Authentication => {
      ...
      validate_user => sub (@args) { $am->validate_user(@args) },
   });


=head1 ANYTHING ELSE (INCLUDING AUTHOR, COPYRIGHT AND LICENSE)

See documentation for L<MojoX::Authentication>.


=cut

lib/MojoX/Authentication/Model/Role/Local.pm  view on Meta::CPAN

sub handles_username ($self, $controller, $name) {
   return unless defined($name);
   return 'yep' if $self->load_user_by_name($controller, $name);
   return undef;
}

sub hash_secret ($self, $secret) {
   $self->crypt_passphrase->hash_password($secret);
}

sub validate_user ($self, $controller, $name, $secret, $extra) {
   return unless defined($name);
   my $user = $self->load_user_by_name($controller, $name) or return;

#   use Data::Dumper;
#   $controller->log->trace("local validate user <$name>, loaded: "
#      . Dumper($user));

   my $cp = $self->crypt_passphrase;
   my $check = $cp->verify_password($secret, $user->{secret});
   return $check ? $name : undef;  # externally visible id is $name
}

1;

lib/MojoX/Authentication/Model/Role/Local.pod  view on Meta::CPAN


Returns a true value if the provider handles the provided username,
false otherwise. Useful to figure out what provider supports a username.

=head2 B<< hash_secret >>

   my $hashed = $provider->hash_secret($secret);

Wrapper for C<< $provider->crypt_passphrase->hash_password($secret) >>.

=head2 B<< validate_user >>

   my $uid = $provider->validate_user($controller, $name, $secret, $extra);

Validate the user identified by C<$name> against the provided
C<$secret>. Parameter C<$extra> is ignored and only present to support
the right signature.

This method calls method C<load_user_by_name> that must be provided by
the class compositing the role.


=head1 ANYTHING ELSE (INCLUDING AUTHOR, COPYRIGHT AND LICENSE)

lib/MojoX/Authentication/Model/SAML2.pm  view on Meta::CPAN

     or ouch 400, 'Invalid SAMLResponse';

   my $uid = $assertion->nameid;
   my $user = $self->_normalize_user(
      { $assertion->attributes->%*, $self->user_key => $uid, });
   $self->_cache_user($user);

   return $user;
}

# this should never (arguably) be called if "auto_validate" in
# Mojolicious::Plugin::Authentication is used. Anyway...
sub validate_user ($self, $controller, $name, $secret, $extra) {
   ...;
   return defined($self->load_user($name)) ? $name : undef;
}

sub wipe_user ($self, $user) { $self->cache->wipe(__key(user => $user)) }

1;

lib/MojoX/Authentication/Model/SAML2.pod  view on Meta::CPAN


=head2 B<< username_validator >>

   my $sub = $provider->username_validator;

Accessor for the username validation function. This is wrapped by
L</handles_username> behind the scenes, so it should be set to some
validation mechanism that allows figuring out if the specific SAML2
Identity Provider is the right one for the username.

=head2 B<< validate_user >>

   my $uid = $provider->validate_user($ctr, $user, $secret, $extra);

Do the user validation, compatibly with
L<Mojolicious::Plugin::Authentication>.
   

=head2 B<< wipe_user >>

   $provider->wipe_user($user);

Remove the user from the cache.



( run in 1.146 second using v1.01-cache-2.11-cpan-0b5f733616e )