2 # PLCAPI authentication parameters
4 # Mark Huang <mlhuang@cs.princeton.edu>
5 # Copyright (C) 2006 The Trustees of Princeton University
7 # $Id: Auth.py,v 1.1 2006/09/06 15:36:06 mlhuang Exp $
12 from PLC.Faults import *
13 from PLC.Parameter import Parameter, Mixed
14 from PLC.Persons import Persons
16 class Auth(Parameter, dict):
18 Base class for all API authentication methods.
21 def __init__(self, auth):
22 Parameter.__init__(self, auth, "API authentication structure", False)
27 PlanetLab version 3.x node authentication structure. Used by the
28 Boot Manager to make authenticated calls to the API based on a
29 unique node key or boot nonce value.
34 'AuthMethod': Parameter(str, "Authentication method to use, always 'hmac'", False),
35 'node_id': Parameter(str, "Node identifier", False),
36 'node_ip': Parameter(str, "Node primary IP address", False),
37 'value': Parameter(str, "HMAC of node key and method call", False)
40 def check(self, method, auth, *args):
41 # XXX Do HMAC checking
44 class AnonymousAuth(Auth):
46 PlanetLab version 3.x anonymous authentication structure.
51 'AuthMethod': Parameter(str, "Authentication method to use, always 'anonymous'", False),
54 def check(self, method, auth, *args):
55 # Sure, dude, whatever
58 class PasswordAuth(Auth):
60 PlanetLab version 3.x password authentication structure.
65 'AuthMethod': Parameter(str, "Authentication method to use, typically 'password'", False),
66 'Username': Parameter(str, "PlanetLab username, typically an e-mail address", False),
67 'AuthString': Parameter(str, "Authentication string, typically a password", False),
68 'Role': Parameter(str, "Role to use for this call", False)
71 def check(self, method, auth, *args):
72 # Method.type_check() should have checked that all of the
73 # mandatory fields were present.
74 assert auth.has_key('Username')
76 # Get record (must be enabled)
77 persons = Persons(method.api, [auth['Username']], enabled = True)
79 raise PLCAuthenticationFailure, "No such account"
81 person = persons.values()[0]
83 if auth['Username'] == method.api.config.PLC_API_MAINTENANCE_USER:
84 # "Capability" authentication, whatever the hell that was
85 # supposed to mean. It really means, login as the special
86 # "maintenance user" using password authentication. Can
87 # only be used on particular machines (those in a list).
88 sources = method.api.config.PLC_API_MAINTENANCE_SOURCES.split()
89 if method.source is not None and method.source[0] not in sources:
90 raise PLCAuthenticationFailure, "Not allowed to login to maintenance account"
92 # Not sure why this is not stored in the DB
93 password = method.api.config.PLC_API_MAINTENANCE_PASSWORD
95 if auth['AuthString'] != password:
96 raise PLCAuthenticationFailure, "Maintenance account password verification failed"
98 # Compare encrypted plaintext against encrypted password stored in the DB
99 plaintext = auth['AuthString'].encode(method.api.encoding)
100 password = person['password']
102 # Protect against blank passwords in the DB
103 if password is None or password[:12] == "" or \
104 crypt.crypt(plaintext, password[:12]) != password:
105 raise PLCAuthenticationFailure, "Password verification failed"
107 if auth['Role'] not in person['roles']:
108 raise PLCAuthenticationFailure, "Account does not have " + auth['Role'] + " role"
110 if method.roles and auth['Role'] not in method.roles:
111 raise PLCAuthenticationFailure, "Cannot call with " + auth['Role'] + "role"
113 method.caller = person