Skip to content

Commit

Permalink
Full OAuth flow--needs better HTML templates
Browse files Browse the repository at this point in the history
  • Loading branch information
solargroovy committed Dec 17, 2013
1 parent 521f556 commit 7902a2f
Show file tree
Hide file tree
Showing 22 changed files with 1,251 additions and 63 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ parser/semantic.cache
/.settings
*.bak
/i386-linux*
workspace.txt
2 changes: 1 addition & 1 deletion Kynetx/Configure.pm
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ sub set_run_mode {
$mode = $mode || $config->{'RUN_MODE'} || 'production';
$config->{'RUN_MODE'} = $mode;

for my $k (qw/INIT_HOST CB_HOST EVAL_HOST KRL_HOST KNS_PORT COOKIE_DOMAIN OAUTH_CALLBACK_HOST OAUTH_CALLBACK_PORT/) {
for my $k (qw/INIT_HOST CB_HOST EVAL_HOST KRL_HOST KNS_PORT COOKIE_DOMAIN OAUTH_CALLBACK_HOST OAUTH_CALLBACK_PORT LOGIN/) {
$config->{$k} = $config->{$mode}->{$k};
}

Expand Down
1 change: 1 addition & 0 deletions Kynetx/Memcached.pm
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ sub mset_cache {
}

}
$logger->debug("Check cache for $key: ",$memd->get($key));
}

sub flush_cache {
Expand Down
130 changes: 114 additions & 16 deletions Kynetx/Modules/PCI.pm
Original file line number Diff line number Diff line change
Expand Up @@ -371,12 +371,18 @@ sub reset_account_password {
$logger->warn("Reset Password args invalid: ", sub {join(",",@{$args})});
return undef;
}
my $hash = _hash_password($new_password);
return Kynetx::Persistence::KEN::set_authorizing_password($ken,$hash);
return _set_password($ken,$new_password);


}
$funcs->{'reset_password'} = \&reset_account_password;

sub _set_password {
my ($ken,$new_password) = @_;
my $hash = _hash_password($new_password);
return Kynetx::Persistence::KEN::set_authorizing_password($ken,$hash);
}

sub check_username {
my($req_info,$rule_env,$session,$rule_name,$function,$args) = @_;
my $logger = get_logger();
Expand All @@ -388,7 +394,7 @@ sub check_username {
my $uid = $args->[0];
$logger->debug("Check for username ($uid)");
if (defined $uid) {
my $ken = Kynetx::Persistence::KEN::ken_lookup_by_username($uid);
my $ken = _username($uid);
if ($ken) {
return 1;
}
Expand All @@ -397,6 +403,15 @@ sub check_username {
}
$funcs->{'exists'} = \&check_username;

sub _username {
my ($uid) = @_;
my $ken;
if (defined $uid) {
$ken = Kynetx::Persistence::KEN::ken_lookup_by_username($uid);
}
return $ken;
}

sub list_children {
my($req_info,$rule_env,$session,$rule_name,$function,$args) = @_;
my $logger = get_logger();
Expand Down Expand Up @@ -1000,6 +1015,43 @@ sub add_oauth_callback {
}
$funcs->{'add_callback'} = \&add_oauth_callback;

sub add_oauth_app_info {
my($req_info,$rule_env,$session,$rule_name,$function,$args) = @_;
my $logger = get_logger();
my $keys = _key_filter($args);
return 0 unless (pci_authorized($req_info, $rule_env, $session, $keys));
my $developer_eci = $args->[0];
my $app_info= $args->[1];;
my $rid = Kynetx::Rids::get_rid($req_info->{'rid'});
my $ken = Kynetx::Persistence::KEN::get_ken($session,$rid);
$ken = Kynetx::Persistence::KEN::ken_lookup_by_token($developer_eci);
if ($ken && scalar @{$args} >= 1) {
return Kynetx::Persistence::KPDS::add_app_info($ken,$developer_eci,$app_info);
}
return undef;

}
$funcs->{'add_appinfo'} = \&add_oauth_app_info;

sub add_oauth_secret {
my($req_info,$rule_env,$session,$rule_name,$function,$args) = @_;
my $logger = get_logger();
my $keys = _key_filter($args);
return 0 unless (pci_authorized($req_info, $rule_env, $session, $keys));
my $developer_eci = $args->[0];
my $secret = $args->[1];;
my $rid = Kynetx::Rids::get_rid($req_info->{'rid'});
my $ken = Kynetx::Persistence::KEN::get_ken($session,$rid);
$ken = Kynetx::Persistence::KEN::ken_lookup_by_token($developer_eci);
if ($ken && scalar @{$args} >= 1) {
return Kynetx::Persistence::KPDS::set_developer_secret($ken,$developer_eci,$secret);
}
return undef;

}
$funcs->{'add_oauth_secret'} = \&add_oauth_secret;


sub remove_callback {
my($req_info,$rule_env,$session,$rule_name,$function,$args) = @_;
my $logger = get_logger();
Expand All @@ -1026,6 +1078,21 @@ sub remove_callback {
}
$funcs->{'remove_callback'} = \&remove_callback;

sub remove_oauth_app_info {
my($req_info,$rule_env,$session,$rule_name,$function,$args) = @_;
my $logger = get_logger();
my $keys = _key_filter($args);
return 0 unless (pci_authorized($req_info, $rule_env, $session, $keys));
my $developer_eci = $args->[0];
my $ken = Kynetx::Persistence::KEN::ken_lookup_by_token($developer_eci);
if ($ken && $developer_eci) {
my $installed = Kynetx::Persistence::KPDS::remove_callback($ken,$developer_eci);
return $installed->{'value'};
}
return undef;

}
$funcs->{'remove_appinfo'} = \&remove_oauth_app_info;

sub list_callback {
my($req_info,$rule_env,$session,$rule_name,$function,$args) = @_;
Expand All @@ -1042,6 +1109,21 @@ sub list_callback {
}
$funcs->{'list_callback'} = \&list_callback;

sub get_oauth_app_info {
my($req_info,$rule_env,$session,$rule_name,$function,$args) = @_;
my $logger = get_logger();
return 0 unless (pci_authorized($req_info,$rule_env,$session));
my $rid = get_rid($req_info->{'rid'});
my $arg1 = $args->[0];
my $ken = Kynetx::Persistence::KEN::ken_lookup_by_token($arg1);
if ($ken) {
return Kynetx::Persistence::KPDS::get_app_info($ken,$arg1);
}
return undef;

}
$funcs->{'get_appinfo'} = \&get_oauth_app_info;

sub make_request_uri {
my ($req_info,$rule_env,$session,$rule_name,$function,$args) = @_;
my $logger=get_logger();
Expand Down Expand Up @@ -1162,33 +1244,47 @@ sub oauth_authorization_code {
$logger->debug("OAuth code");
my $keys = _key_filter($args);
return unless (pci_authorized($req_info, $rule_env, $session, $keys));
my $t = time();

my $developer_eci = $args->[0];
my $user_eci = $args->[1];
my $developer_secret = $args->[2];
return _construct_oauth_code($developer_eci,$developer_secret,$user_eci);
}
$funcs->{'OAuth_code'} = \&oauth_authorization_code;

sub _construct_oauth_code {
my ($developer_eci,$developer_secret,$user_eci) = @_;
my $t = time();
my $syskey = syskey();
my $oauth_key = "$syskey" ^ "$developer_eci";
my $raw_token = $t . "|" . $developer_eci . "|" . $developer_secret . "|" . $user_eci;
my $encr = RC4($oauth_key,$raw_token);
my $encrypted = unpack('H*', $encr);
my $b64 = MIME::Base64::encode_base64url($encrypted);
return $b64;
return _obfuscate($oauth_key,$raw_token);
}
$funcs->{'OAuth_code'} = \&oauth_authorization_code;

sub deconstruct_oauth_code {
my ($developer_eci,$code) = @_;
my $logger = get_logger();
my $de64 = MIME::Base64::decode_base64url($code);
my $syskey = syskey();
my $oauth_key = "$syskey" ^ "$developer_eci";
my $packed = pack('H*', $de64);
my $decoded = RC4($oauth_key,$packed);
$logger->debug("Length: ", length($de64));
$logger->debug("Code string: ", $decoded);
my $decoded = _fuscate($oauth_key,$code);
my @val = split(/\|/,$decoded);
return \@val;

return \@val;
}

sub _obfuscate {
my ($key,$string) = @_;
my $encr = RC4($key,$string);
my $encrypted = unpack('H*', $encr);
my $b64 = MIME::Base64::encode_base64url($encrypted);
return $b64;
}

sub _fuscate {
my ($key,$estring) = @_;
my $de64 = MIME::Base64::decode_base64url($estring);
my $packed = pack('H*', $de64);
my $decoded = RC4($key,$packed);
return $decoded;
}

sub create_oauth_token {
Expand Down Expand Up @@ -1280,6 +1376,8 @@ sub auth_ken {
my $logger = get_logger();
my $hashed = Kynetx::Persistence::KEN::get_authorizing_password($ken);
my $passed = _hash_password($string);
$logger->debug("hash: $hashed");
$logger->debug("Pass: $passed");
if ($hashed eq $passed) {
return 1;
}
Expand Down
37 changes: 28 additions & 9 deletions Kynetx/OAuth/OAccessToken.pm
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ use Cache::Memcached;
use DateTime::Format::ISO8601;
use Benchmark ':hireswallclock';
use Encode qw(from_to);
use Digest::MD5 qw(md5_base64);

use Kynetx::Util;
use Kynetx::Persistence::KEN qw(
Expand Down Expand Up @@ -96,6 +97,15 @@ sub handler {
$logger->debug("Code: $code");
$logger->debug("Grant: $grant");
$logger->debug("Redirect: $redirect_uri");


my $md5_sig = md5_base64($code);
$logger->debug("Check cache for $md5_sig");
my $code_exists = Kynetx::Memcached::check_cache($md5_sig);
if ($code_exists) {
$logger->debug("Fail on duplicate code");
return return_error($r,$redirect_uri,'invalid_request','Duplicate request codes not allowed');
}
my $decon = Kynetx::Modules::PCI::deconstruct_oauth_code($user,$code);
my $time = $decon->[0];
my $eci = $decon->[1];
Expand All @@ -105,9 +115,16 @@ sub handler {
$logger->debug("Client Id/Developer code mis-match");
return Apache2::Const::HTTP_BAD_REQUEST;
}

$logger->debug("Time: $time");
$logger->debug("ECI: $eci");
$logger->debug("secret: $secret");
$logger->debug("oauth user: ", sub {Dumper($oauth_user)});
my $now = time();
my $elapsed = $now - $time;
return_error($r,$redirect_uri,'invalid_request',"Request token code is stale") unless ($elapsed < $TEN_MINUTES);
return return_error($r,$redirect_uri,'invalid_request',"Request token code is stale") unless ($elapsed < $TEN_MINUTES);



# so far so good, now create the official token
my $token = Kynetx::Modules::PCI::create_oauth_token($cid,$oauth_user,$secret);
Expand All @@ -116,6 +133,10 @@ sub handler {
my $oauth_eci = Kynetx::Modules::PCI::create_oauth_indexed_eci($ken,$token,$eci);
$logger->debug("OECI: $oauth_eci");

# store the code in memcached so it can't be used again

Kynetx::Memcached::mset_cache($md5_sig,1,6060);

# Server response
$r->content_type('application/json;charset=UTF-8');
$r->headers_out->set('Cache-Control' => 'no-store');
Expand All @@ -127,14 +148,12 @@ sub handler {

sub return_error {
my ($r,$uri,$code,$description) = @_;
my $params = {
"error" => $code,
"error_description" => $description
};
my $redirect = Kynetx::Util::mk_url($uri,$params);
$r->headers_out->set('Location' => $redirect);
$r->status(Apache2::Const::HTTP_TEMPORARY_REDIRECT);
return Apache2::Const::OK;
$r->content_type('application/json;charset=UTF-8');
$r->headers_out->set('Cache-Control' => 'no-store');
$r->headers_out->set('Pragma' => 'no-cache');
$r->status(Apache2::Const::HTTP_BAD_REQUEST);
$r->custom_response(Apache2::Const::HTTP_BAD_REQUEST, "{\n \"error\":\"$code\",\n \"error_description\":\"$description\"\n}");
return Apache2::Const::HTTP_BAD_REQUEST;
}

1;
Loading

0 comments on commit 7902a2f

Please sign in to comment.