CatalystX-OAuth2

 view release on metacpan or  search on metacpan

lib/Catalyst/ActionRole/OAuth2/AuthToken/ViaAuthGrant.pm  view on Meta::CPAN

package Catalyst::ActionRole::OAuth2::AuthToken::ViaAuthGrant;
use Moose::Role;
use Try::Tiny;
use CatalystX::OAuth2::Request::AuthToken;

# ABSTRACT: Authorization token provider endpoint for OAuth2 authentication flows


with 'CatalystX::OAuth2::ActionRole::Token';

sub build_oauth2_request {
  my ( $self, $controller, $c ) = @_;

  my $store = $controller->store;
  my $req;

lib/Catalyst/ActionRole/OAuth2/AuthToken/ViaAuthGrant.pm  view on Meta::CPAN

}

1;

__END__

=pod

=head1 NAME

Catalyst::ActionRole::OAuth2::AuthToken::ViaAuthGrant - Authorization token provider endpoint for OAuth2 authentication flows

=head1 VERSION

version 0.001009

=head1 SYNOPSIS

    package AuthServer::Controller::OAuth2::Provider;
    use Moose;

lib/Catalyst/ActionRole/OAuth2/AuthToken/ViaAuthGrant.pm  view on Meta::CPAN

        client_model => 'DB::Client'
      }
    );

    sub token : Chained('/') Args(0) Does('OAuth2::AuthToken::ViaAuthGrant') {}

    1;

=head1 DESCRIPTION

This action role implements an endpoint that exchanges an authorization code
for an access token.

=head1 AUTHOR

Eden Cardim <edencardim@gmail.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2017 by Suretec Systems Ltd.

lib/Catalyst/ActionRole/OAuth2/AuthToken/ViaRefreshToken.pm  view on Meta::CPAN

package Catalyst::ActionRole::OAuth2::AuthToken::ViaRefreshToken;
use Moose::Role;
use Try::Tiny;
use CatalystX::OAuth2::Request::RefreshToken;

# ABSTRACT: Authorization token refresh provider endpoint for OAuth2 authentication flows


with 'CatalystX::OAuth2::ActionRole::Token';

sub build_oauth2_request {
  my ( $self, $controller, $c ) = @_;

  my $store = $controller->store;
  my $req;

lib/Catalyst/ActionRole/OAuth2/AuthToken/ViaRefreshToken.pm  view on Meta::CPAN

}

1;

__END__

=pod

=head1 NAME

Catalyst::ActionRole::OAuth2::AuthToken::ViaRefreshToken - Authorization token refresh provider endpoint for OAuth2 authentication flows

=head1 VERSION

version 0.001009

=head1 SYNOPSIS

    package AuthServer::Controller::OAuth2::Provider;
    use Moose;

lib/Catalyst/ActionRole/OAuth2/AuthToken/ViaRefreshToken.pm  view on Meta::CPAN

        client_model => 'DB::Client'
      }
    );

    sub refresh : Chained('/') Args(0) Does('OAuth2::AuthToken::ViaRefreshToken') {}

    1;

=head1 DESCRIPTION

This action role implements an endpoint that exchanges a refresh token for an
access token.

=head1 AUTHOR

Eden Cardim <edencardim@gmail.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2017 by Suretec Systems Ltd.

lib/Catalyst/ActionRole/OAuth2/GrantAuth.pm  view on Meta::CPAN

package Catalyst::ActionRole::OAuth2::GrantAuth;
use Moose::Role;
use Try::Tiny;
use CatalystX::OAuth2::Request::GrantAuth;

# ABSTRACT: Authorization grant endpoint for OAuth2 authentication flows


with 'CatalystX::OAuth2::ActionRole::Grant';

sub build_oauth2_request {
  my ( $self, $controller, $c ) = @_;

  my $store = $controller->store;
  my $req;
  try {

lib/Catalyst/ActionRole/OAuth2/GrantAuth.pm  view on Meta::CPAN

}

1;

__END__

=pod

=head1 NAME

Catalyst::ActionRole::OAuth2::GrantAuth - Authorization grant endpoint for OAuth2 authentication flows

=head1 VERSION

version 0.001009

=head1 SYNOPSIS

    package AuthServer::Controller::OAuth2::Provider;
    use Moose;
    BEGIN { extends 'Catalyst::Controller::ActionRole' }

lib/Catalyst/ActionRole/OAuth2/GrantAuth.pm  view on Meta::CPAN

      my ( $self, $c ) = @_;

      my $oauth2 = $c->req->oauth2;

      $c->user_exists and $oauth2->user_is_valid(1)
        or $c->detach('/passthrulogin');
    }

=head1 DESCRIPTION

This action role implements the authorization confirmation endpoint that asks
the user if he wishes to grant resource access to the client. This is
generally done by presenting a form to the user. Regardless of the mechanism
used for this confirmation, the C<$c->req->oauth2> object must be informed of
the user's decision via the C<user_is_valid> attribute, which must be true by
the end of the request, in order for the authorization flow to be continued.

=head1 AUTHOR

Eden Cardim <edencardim@gmail.com>

lib/Catalyst/ActionRole/OAuth2/ProtectedResource.pm  view on Meta::CPAN

package Catalyst::ActionRole::OAuth2::ProtectedResource;
use Moose::Role;
use CatalystX::OAuth2::Request::ProtectedResource;

# ABSTRACT: Resource endpoint for OAuth2 authentication flows


with 'CatalystX::OAuth2::ActionRole::RequestInjector';

sub build_oauth2_request {
  my ( $self, $controller, $c ) = @_;

  my $auth = $c->req->header('Authorization')
    or $c->res->status(401), $c->detach;
  my ( $type, $token ) = split ' ', $auth;

lib/Catalyst/ActionRole/OAuth2/ProtectedResource.pm  view on Meta::CPAN

}

1;

__END__

=pod

=head1 NAME

Catalyst::ActionRole::OAuth2::ProtectedResource - Resource endpoint for OAuth2 authentication flows

=head1 VERSION

version 0.001009

=head1 SYNOPSIS

    package AuthServer::Controller::OAuth2::Resource;
    use Moose;

lib/Catalyst/ActionRole/OAuth2/ProtectedResource.pm  view on Meta::CPAN

      }
    );

    sub resource : Chained('/') Args(0) Does('OAuth2::ProtectedResource') {
      my ( $self, $c ) = @_;
      $c->res->body( 'my protected resource' );
    }

=head1 DESCRIPTION

This action role implements an arbitrary resource endpoint to be protected by
the authorization flow. Clients will only be able to access this resource if
they provide a valid access token. The action body should be customized like a
regular action.

=head1 AUTHOR

Eden Cardim <edencardim@gmail.com>

=head1 COPYRIGHT AND LICENSE

lib/Catalyst/ActionRole/OAuth2/RequestAuth.pm  view on Meta::CPAN

package Catalyst::ActionRole::OAuth2::RequestAuth;
use Moose::Role;
use Try::Tiny;
use URI;
use CatalystX::OAuth2::Request::RequestAuth;

# ABSTRACT: Authorization grant endpoint for OAuth2 authentication flows


with 'CatalystX::OAuth2::ActionRole::Grant';

has enable_client_secret => ( isa => 'Bool', is => 'ro', default => 0 );

sub build_oauth2_request {
  my ( $self, $controller, $c ) = @_;

  my $store = $controller->store;

lib/Catalyst/ActionRole/OAuth2/RequestAuth.pm  view on Meta::CPAN

}

1;

__END__

=pod

=head1 NAME

Catalyst::ActionRole::OAuth2::RequestAuth - Authorization grant endpoint for OAuth2 authentication flows

=head1 VERSION

version 0.001009

=head1 SYNOPSIS

    package AuthServer::Controller::OAuth2::Provider;
    use Moose;
    BEGIN { extends 'Catalyst::Controller::ActionRole' }

lib/Catalyst/ActionRole/OAuth2/RequestAuth.pm  view on Meta::CPAN

      store => {
        class => 'DBIC',
        client_model => 'DB::Client'
      }
    );

    sub request : Chained('/') Args(0) Does('OAuth2::RequestAuth') {}

=head1 DESCRIPTION

This action role implements the initial endpoint that triggers the
authorization grant flow. It generates an inactive authorization code
redirects to the next action in the workflow if all parameters are valid. The
authorization code is used to verify the validity of the arguments in the
subsequent request of the flow and prevent users of this library from creating
potentially unsafe front-end forms for user confirmation of the authorization.

=head1 AUTHOR

Eden Cardim <edencardim@gmail.com>

lib/CatalystX/OAuth2.pm  view on Meta::CPAN

package CatalystX::OAuth2;
use Moose::Role;

# ABSTRACT: OAuth2 services for Catalyst


requires '_build_query_parameters';

# spec isn't clear re missing endpoint uris
has redirect_uri  => ( is => 'ro', required => 0 );

has store => (
  is        => 'rw',
  does      => 'CatalystX::OAuth2::Store',
  init_arg  => undef,
  predicate => 'has_store'
);

has query_parameters => ( is => 'rw', init_arg => undef, lazy_build => 1 );

lib/CatalystX/OAuth2.pm  view on Meta::CPAN

    sub token : Chained('/') Args(0) Does('OAuth2::AuthToken::ViaAuthGrant') {}

    sub refresh : Chained('/') Args(0) Does('OAuth2::AuthToken::ViaRefreshToken') {}

    1;

=head1 DESCRIPTION

This module implements the authorization grant subset of the L<oauth 2 ietf
spec draft|http://tools.ietf.org/html/draft-ietf-oauth-v2-23>. Action roles
containing an implementation of each required endpoint in the specification
are provided and should be applied to a L<Catalyst::Controller::ActionRole>.
The authorization grant flow is defined by the specification as follows:

  +--------+                                           +---------------+
  |        |--(A)------- Authorization Grant --------->|               |
  |        |                                           |               |
  |        |<-(B)----------- Access Token -------------|               |
  |        |               & Refresh Token             |               |
  |        |                                           |               |
  |        |                            +----------+   |               |

lib/CatalystX/OAuth2.pm  view on Meta::CPAN

request parameters if a valid authorization code is presented.

=item B - L<Catalyst::ActionRole::OAuth2::GrantAuth>

Required

This action checks the request parameters for a valid authorization code,
which should have been generated by a previous request to a RequestAuth
action. This action should be customized to somehow confirm with the end-user
if he wishes to effectively grant the authorization to the requesting
client/app. The user-agent is redirected automatically to the correct endpoint
if the authorization is granted.

=item C and D - L<Catalyst::ActionRole::OAuth2::AuthToken::ViaAuthGrant>

Required

This action exchanges a valid authorization grant code and responds with an
authorization token.

=item G and H - L<Catalyst::ActionRole::OAuth2::AuthToken::ViaRefreshToken>

lib/CatalystX/OAuth2/Request/RequestAuth.pm  view on Meta::CPAN

    or return {
    error             => 'unauthorized_client',
    error_description => 'the client identified by '
      . $self->client_id
      . ' is not authorized to access this resource'
    }
    if $self->enable_client_secret;

  $q{client_id} = $self->client_id;

  $client->endpoint eq $self->redirect_uri
    or return {
    error => 'invalid_request',
    error_description =>
      'redirection_uri does not match the registered client endpoint'
    };

  $q{redirect_uri} = $self->redirect_uri;

  my $code = $store->create_client_code( $self->client_id );
  $q{code} = $code->as_string;

  return \%q;
}

lib/CatalystX/OAuth2/Schema/Result/Client.pm  view on Meta::CPAN

package CatalystX::OAuth2::Schema::Result::Client;
use parent 'DBIx::Class';

# ABSTRACT: A table for registering clients

__PACKAGE__->load_components(qw(Core));
__PACKAGE__->table('client');
__PACKAGE__->add_columns(
  id            => { data_type => 'int',  is_auto_increment => 1 },
  endpoint      => { data_type => 'text', is_nullable       => 0 },
  client_secret => { data_type => 'text', is_nullable       => 1 }
);
__PACKAGE__->set_primary_key('id');
__PACKAGE__->has_many( codes => 'CatalystX::OAuth2::Schema::Result::Code' =>
    { 'foreign.client_id' => 'self.id' } );

sub find_refresh {
  shift->codes->search( { is_active => 1 } )
    ->related_resultset('refresh_tokens')->find(@_);
}

lib/CatalystX/OAuth2/Store.pm  view on Meta::CPAN

package CatalystX::OAuth2::Store;
use Moose::Role;

# ABSTRACT: The API for oauth2 stores

requires qw(
  find_client
  client_endpoint
  create_client_code
  client_code_is_active
  activate_client_code
  deactivate_client_code
  create_access_token
  find_client_code
  verify_client_secret
  verify_client_token
);

lib/CatalystX/OAuth2/Store/DBIC.pm  view on Meta::CPAN

has client_model => (
  isa      => 'Str',
  is       => 'ro',
  required => 1
);
has _client_model => (
  isa        => 'DBIx::Class::ResultSet',
  is         => 'ro',
  lazy_build => 1
);
has endpoint_field => ( isa => 'Str', is => 'ro', default => 'endpoint' );
has refresh_relation =>
  ( isa => 'Str', is => 'ro', default => 'refresh_tokens' );
has token_relation => ( isa => 'Str', is => 'ro', default => 'tokens' );
has code_relation  => ( isa => 'Str', is => 'ro', default => 'codes' );
has code_activation_field =>
  ( isa => 'Str', is => 'ro', default => 'is_active' );

sub _build__client_model {
  my ($self) = @_;
  return $self->app->model( $self->client_model );
}

sub find_client {
  my ( $self, $id ) = @_;
  $self->_client_model->find($id);
}

sub client_endpoint {
  my ( $self, $id ) = @_;
  my $client = $self->find_client($id)
    or return;
  return $client->get_column( $self->endpoint_field );
}

sub _code_rs {
  my ( $self, $id ) = @_;
  return $self->_client_model->related_resultset( $self->code_relation )
    unless defined($id);
  my $client = $self->find_client($id)
    or return;
  return $client->related_resultset( $self->code_relation );
}

t/lib/AuthServer/Model/DB.pm  view on Meta::CPAN

package AuthServer::Model::DB;
use Moose;

BEGIN { extends 'Catalyst::Model::DBIC::Schema' }

has user_endpoint =>
  ( isa => 'Str', is => 'ro', default => sub {'http://localhost/auth'} );

__PACKAGE__->config(
  schema_class => 'CatalystX::OAuth2::Schema',
  connect_info => [ 'dbi:SQLite:dbname=:memory:', '', '' ]
);

around COMPONENT => sub {
  my $orig  = shift;
  my $class = shift;
  my $self  = $class->$orig(@_);
  $self->schema->deploy;
  $self->schema->resultset('Client')
    ->create(
    { endpoint => $self->user_endpoint, client_secret => 'foosecret' } );
  return $self;
};

1;

t/unit/300-actionrole-grant-auth.t  view on Meta::CPAN

use strictures 1;
use Test::More;

use HTTP::Request::Common;
use lib 't/lib';
use Catalyst::Test 'AuthServer';


my $code =
  AuthServer->model('DB::Code')
  ->create( { client => { endpoint => '/client/foo' } } );

# try grant with invalid code and no approval param
# should display form
{
  my $uri = URI->new('/grant');
  $uri->query_form(
    { response_type => 'code',
      client_id     => 1,
      state         => 'bar',
      code          => 999999,

t/unit/400-actionrole-auth-token-via-auth-grant.t  view on Meta::CPAN

use Test::More;
use JSON::Any;
use HTTP::Request::Common;
use lib 't/lib';
use Catalyst::Test 'AuthServer';

my $json = JSON::Any->new;


my $code = AuthServer->model('DB::Code')
  ->create( { client => { endpoint => '/client/foo' } } );

{
  my $uri = URI->new('/token');
  $uri->query_form(
    { grant_type   => 'authorization_code',
      redirect_uri => '/client/foo',
      code         => $code->as_string
    }
  );
  my ($res2, $c) = ctx_request($uri);

t/unit/500-actionrole-auth-token-via-refresh-token.t  view on Meta::CPAN

use Test::More;
use JSON::Any;
use HTTP::Request::Common;
use lib 't/lib';
use Catalyst::Test 'AuthServer';

my $json = JSON::Any->new;


my $code = AuthServer->model('DB::Code')->create(
  { client    => { endpoint => '/client/foo' },
    is_active => 1
  }
);

my $refresh;

{
  my $uri = URI->new('/withrefresh/token');
  $uri->query_form(
    { grant_type   => 'authorization_code',



( run in 0.287 second using v1.01-cache-2.11-cpan-e5176c747c2 )