1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
|
###########################################
package Net::SSH::AuthorizedKey;
###########################################
use strict;
use warnings;
use Log::Log4perl qw(:easy);
use Net::SSH::AuthorizedKey::SSH1;
use Net::SSH::AuthorizedKey::SSH2;
###########################################
sub parse {
###########################################
my($class, $string) = @_;
my @subclasses = qw(
Net::SSH::AuthorizedKey::SSH1
Net::SSH::AuthorizedKey::SSH2
);
for my $subclass ( @subclasses ) {
DEBUG "Parsing with $subclass: $string";
my $pk = $subclass->parse( $string );
if($pk) {
DEBUG "Successfully parsed $subclass key";
return $pk;
}
}
return undef;
}
1;
__END__
=head1 NAME
Net::SSH::AuthorizedKey - Virtual Base Class for SSH Public Keys
=head1 SYNOPSIS
use Net::SSH::AuthorizedKey;
# Either parse a string (without leading whitespace or comments):
my $key = Net::SSH::AuthorizedKey->parse( $line );
if(defined $key) {
# ssh-1 or ssh-2
print "Key parsed, type is ", $key->type(), "\n";
} else {
die "Cannot parse key '$line'";
}
# ... or create an object yourself:
my $pubkey = Net::SSH::AuthorizedKey->new(
options => { from => 'foo@bar.com',
"no-agent-forwarding" => 1 },
key => "123....890",
keylen => 1024,
exponent => 35,
type => "ssh-1",
);
=head1 DESCRIPTION
Net::SSH::AuthorizedKey is a virtual base class for ssh public keys.
Real implementations of it are Net::SSH::AuthorizedKey::SSH1 and
Net::SSH::AuthorizedKey::SSH2.
The only way to using it directly is by calling its parse() method, and passing
it an authorized_keys string (aka a line from an authorized_keys file). If it
recognizes either a ssh-1 or a ssh-2 type key, it will return a
Net::SSH::AuthorizedKey::SSH1 or a Net::SSH::AuthorizedKey::SSH2 object, both
of which support the accessor methods defined in the FIELDS section below.
The as_string() method will cobble the (perhaps modified) fields together
and return them as a string suitable as a line for an authorized_keys file.
=head2 METHODS
=over 4
=item C<parse( $line )>
Reads in a single text line containing a ssh-1 or ssh-2 key.
Returns a Net::SSH::AuthorizedKey::SSH1 or a Net::SSH::AuthorizedKey::SSH2
object, or C<undef> in case of an error.
=item C<fingerprint()>
Returns a MD5 hex hash of the parsed key. The hash is unique for functionally
identical keys. Fields not contributing to the key's functional uniqueness
are ignored.
=item C<error()>
Returns the last parsing error encountered as a text string.
=item C<as_string( )>
Return the object as a string suitable as a autorized_keys line.
=back
=head2 FIELDS
All of the following fields are available via accessors:
=over 4
=item C<type>
Type of ssh key, usually C<"ssh-1"> or C<"ssh-2">.
=item C<key>
Public key, either a long number (ssh-1) or a line of alphanumeric
characters (ssh-2).
=item C<keylen>
Length of the key in bit (e.g. 1024).
=item C<exponent>
Two-digit number in front of the key in ssh-1 authorized_keys lines.
=item C<options>
Returns a reference to a hash with options key/value pairs, listed in
front of the key.
=back
=head2 IMPLEMENTATION REFERENCE
The key parsers implemented in this distribution are implemented similarily
as the authorized_keys file parser in the openssh source distribution.
Openssh contains the authorized_keys parser
in its auth2_pubkey.c file. The user_key_allowed2() function opens
the file and reads it line by line, ignoring leading whitespace, empty
and comment lines.
After that, if a line doesn't contain a plain key, the parser skips ahead until
the first whitespace (zooming through quoted areas "..." and interpreting '\"'
as an escaped quote), then skips this whitespace and tries to read a key one
more time.
Regarding options, the Perl parser isn't as elaborate with semantic
peculiarities as openssh's auth_parse_options(), but this might be
added in the future.
=head1 NOTES FOR SUBCLASS DEVELOPERS
If you're just using Net::SSH::AuthorizedKey to parse keys, the
following section doesn't concern you. It's only relevant if you add
new subclasses to this package, on top of what's already provided.
Net::SSH::AuthorizedKey is a (semi-)virtual base class that implements
options handling for its SSH1 and SSH2 subclasses.
SSH key lines can contain options that carry values (like command="ls") and
binary options that are either set or unset (like "no_agent_forwarding"). To
distinguish the two, and to provide a set of allowed option names, the subclass
has to implement the method option_type(), which takes an option name, and
returns
=over 4
=item *
undef if the option is not supported
=item *
"s" if the option is a "string" option that carries a value
=item *
1 if the option is a binary option
=back
The subclasses Net::SSH::AuthorizedKey::SSH1 and Net::SSH::AuthorizedKey::SSH2
are doing this already.
=head1 LEGALESE
Copyright 2005-2009 by Mike Schilli, all rights reserved.
This program is free software, you can redistribute it and/or
modify it under the same terms as Perl itself.
=head1 AUTHOR
2005, Mike Schilli <m@perlmeister.com>
|