File Coverage

lib/OAuthomatic/SecretStorage/Keyring.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package OAuthomatic::SecretStorage::Keyring;
2             # ABSTRACT: Save tokens in secure storage, using L<Passwd::Keyring::Auto>
3              
4 1     1   914 use Moose;
  0            
  0            
5             use namespace::sweep;
6             use MooseX::AttributeShortcuts;
7             use Passwd::Keyring::Auto qw(get_keyring);
8             use Const::Fast;
9              
10              
11             has 'config' => (
12             is => 'ro', isa => 'OAuthomatic::Config', required => 1,
13             handles => [
14             'app_name',
15             'password_group',
16             'debug',
17             ]);
18              
19              
20             has 'server' => (
21             is => 'ro', isa => 'OAuthomatic::Server', required => 1,
22             handles => [
23             'site_name',
24             ]);
25              
26              
27             has 'keyring' => (
28             is => 'lazy', trigger => sub {
29             my ($self, $keyring, $old_val) = @_;
30             unless($keyring->is_persistent) {
31             OAuthomatic::Error::Generic->throw(
32             ident => "Attempt to use non-persistent keyring",
33             extra => "Suggested backend is non-persistent: ") . ref($keyring) . ".\n";
34             }
35             });
36              
37             sub _build_keyring {
38             my $self = shift;
39             my $password_group = $self->password_group;
40             my $app_name = $self->app_name;
41             OAuthomatic::Error::Generic->throw(
42             ident => "Bad parameter",
43             extra => "You must specify password_group and app_name (or specify keyring)")
44             unless ($password_group && $app_name);
45             my $keyring = get_keyring(group => $password_group,
46             app => $app_name);
47             unless($keyring->is_persistent) {
48             OAuthomatic::Error::Generic->throw(
49             ident => "Bad keyring configuration",
50             extra => "Got non-persistent keyring backend (") . ref($keyring) . "). Reconfigure Passwd::Keyring::Auto (and maybe install some Passwd::Keyring::<backend>) to use something non-volatile.\n";
51             }
52             if($self->debug) {
53             print "[OAuthomatic] Constructed keyring. Type: ", ref($keyring), ", app: $app_name, group: $password_group\n";
54             }
55             return $keyring;
56             }
57              
58             const my $CLIENT_MAP_KEY => "oauthomatic_client_key";
59              
60             sub get_client_cred {
61             my ($self) = @_;
62              
63             my $client_key = $self->keyring->get_password($CLIENT_MAP_KEY, $self->site_name);
64             return unless $client_key;
65             my $client_secret = $self->keyring->get_password($client_key, $self->site_name);
66             return unless $client_secret;
67             return OAuthomatic::Types::ClientCred->new(
68             key => $client_key,
69             secret => $client_secret,
70             );
71             }
72              
73             sub save_client_cred {
74             my ($self, $client) = @_;
75              
76             $self->keyring->set_password($client->key, $client->secret, $self->site_name);
77             $self->keyring->set_password($CLIENT_MAP_KEY, $client->key, $self->site_name);
78             }
79              
80             sub clear_client_cred {
81             my ($self) = @_;
82              
83             # FIXME: give an option of clearing only mapping but keeping key in storage?
84              
85             my $client_key = $self->keyring->get_password($CLIENT_MAP_KEY, $self->site_name);
86             return unless $client_key;
87              
88             $self->keyring->clear_password($client_key, $self->site_name);
89             $self->keyring->clear_password($CLIENT_MAP_KEY, $self->site_name);
90             }
91              
92             const my $TOKEN_MAP_KEY => "oauthomatic_token";
93              
94             sub get_token_cred {
95             my ($self) = @_;
96              
97             my $token = $self->keyring->get_password($TOKEN_MAP_KEY, $self->site_name);
98             return unless $token;
99             my $token_secret = $self->keyring->get_password($token, $self->site_name);
100             return unless $token_secret;
101             return OAuthomatic::Types::TokenCred->new(
102             token => $token,
103             secret => $token_secret,
104             );
105             }
106              
107             sub save_token_cred {
108             my ($self, $access) = @_;
109              
110             $self->keyring->set_password($access->token, $access->secret, $self->site_name);
111             $self->keyring->set_password($TOKEN_MAP_KEY, $access->token, $self->site_name);
112             }
113              
114             sub clear_token_cred {
115             my ($self) = @_;
116              
117             my $token = $self->keyring->get_password($TOKEN_MAP_KEY, $self->site_name);
118             return unless $token;
119              
120             $self->keyring->clear_password($token, $self->site_name);
121             $self->keyring->clear_password($TOKEN_MAP_KEY, $self->site_name);
122             }
123              
124             with 'OAuthomatic::SecretStorage';
125              
126             1;
127              
128             __END__
129              
130             =pod
131              
132             =encoding UTF-8
133              
134             =head1 NAME
135              
136             OAuthomatic::SecretStorage::Keyring - Save tokens in secure storage, using L<Passwd::Keyring::Auto>
137              
138             =head1 VERSION
139              
140             version 0.01
141              
142             =head1 DESCRIPTION
143              
144             Implements L<OAuthomatic::SecretStorage> interface using
145             L<Passwd::Keyring::Auto> (what usually means saving data in Gnome
146             Keyring, KDE Wallet, Windows Vault or similar secure storage).
147              
148             Note that tokens are saved in slightly specific way. Whenever client
149             key is saved, we create two entries in keyring:
150              
151             username: client_key
152             password: client_secret
153              
154             and
155              
156             username: "oauthomatic_client_key"
157             password: client_key
158              
159             The former is natural. The latter helps find what current key is
160             (this record is not very secret but it is easier to keep it too
161             than invent second configuration backend).
162              
163             Access tokens are treated similarly:
164              
165             username: token
166             password: token_secret
167              
168             and
169              
170             username: "oauthomatic_token"
171             password: token
172              
173             =head1 ATTRIBUTES
174              
175             =head2 config
176              
177             L<OAuthomatic::Config> object used to bundle various configuration params.
178              
179             =head2 server
180              
181             L<OAuthomatic::Server> object used to bundle server-related configuration params.
182              
183             =head2 keyring
184              
185             Actual password backend in use.
186              
187             Usually initialized automatically, guessing best possible password
188             backend (according to L<Passwd::Keyring::Auto> selection and using
189             it's C<app_name> and C<password_group> attributes), but can be
190             specified if application prefers to use sth. specific:
191              
192             keyring => Passwd::Keyring::KDEWallet->new(...))
193              
194             =head1 AUTHOR
195              
196             Marcin Kasperski <Marcin.Kasperski@mekk.waw.pl>
197              
198             =head1 COPYRIGHT AND LICENSE
199              
200             This software is copyright (c) 2015 by Marcin Kasperski.
201              
202             This is free software; you can redistribute it and/or modify it under
203             the same terms as the Perl 5 programming language system itself.
204              
205             =cut