864
756
return osutils.pathjoin(config_dir(), 'locations.conf')
867
def authentication_config_filename():
868
"""Return per-user authentication ini file filename."""
869
return osutils.pathjoin(config_dir(), 'authentication.conf')
872
759
def user_ignore_config_filename():
873
760
"""Return the user default ignore filename"""
874
761
return osutils.pathjoin(config_dir(), 'ignore')
878
"""Return the directory name to store crash files.
880
This doesn't implicitly create it.
882
On Windows it's in the config directory; elsewhere it's /var/crash
883
which may be monitored by apport. It can be overridden by
765
"""Calculate automatic user identification.
767
Returns (realname, email).
769
Only used when none is set in the environment or the id file.
771
This previously used the FQDN as the default domain, but that can
772
be very slow on machines where DNS is broken. So now we simply
886
777
if sys.platform == 'win32':
887
return osutils.pathjoin(config_dir(), 'Crash')
889
# XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
891
return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
895
# See http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
896
# Possibly this should be different on Windows?
897
e = os.environ.get('XDG_CACHE_DIR', None)
901
return os.path.expanduser('~/.cache')
904
def parse_username(username):
905
"""Parse e-mail username and return a (name, address) tuple."""
906
match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
908
return (username, '')
910
return (match.group(1), match.group(2))
778
name = win32utils.get_user_name_unicode()
780
raise errors.BzrError("Cannot autodetect user name.\n"
781
"Please, set your name with command like:\n"
782
'bzr whoami "Your Name <name@domain.com>"')
783
host = win32utils.get_host_name_unicode()
785
host = socket.gethostname()
786
return name, (name + '@' + host)
791
w = pwd.getpwuid(uid)
793
# we try utf-8 first, because on many variants (like Linux),
794
# /etc/passwd "should" be in utf-8, and because it's unlikely to give
795
# false positives. (many users will have their user encoding set to
796
# latin-1, which cannot raise UnicodeError.)
798
gecos = w.pw_gecos.decode('utf-8')
802
gecos = w.pw_gecos.decode(bzrlib.user_encoding)
803
encoding = bzrlib.user_encoding
805
raise errors.BzrCommandError('Unable to determine your name. '
806
'Use "bzr whoami" to set it.')
808
username = w.pw_name.decode(encoding)
810
raise errors.BzrCommandError('Unable to determine your name. '
811
'Use "bzr whoami" to set it.')
813
comma = gecos.find(',')
817
realname = gecos[:comma]
824
realname = username = getpass.getuser().decode(bzrlib.user_encoding)
825
except UnicodeDecodeError:
826
raise errors.BzrError("Can't decode username as %s." % \
827
bzrlib.user_encoding)
829
return realname, (username + '@' + socket.gethostname())
913
832
def extract_email_address(e):
914
833
"""Return just the address part of an email string.
916
That is just the user@domain part, nothing else.
835
That is just the user@domain part, nothing else.
917
836
This part is required to contain only ascii characters.
918
837
If it can't be extracted, raises an error.
920
839
>>> extract_email_address('Jane Tester <jane@test.com>')
923
name, email = parse_username(e)
842
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
925
844
raise errors.NoEmailInUsername(e)
929
848
class TreeConfig(IniBasedConfig):
930
849
"""Branch configuration data associated with its contents, not location"""
932
# XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
934
850
def __init__(self, branch):
935
self._config = branch._get_config()
936
851
self.branch = branch
938
853
def _get_parser(self, file=None):
939
854
if file is not None:
940
855
return IniBasedConfig._get_parser(file)
941
return self._config._get_configobj()
856
return self._get_config()
858
def _get_config(self):
860
obj = ConfigObj(self.branch.control_files.get('branch.conf'),
862
except errors.NoSuchFile:
863
obj = ConfigObj(encoding='utf=8')
943
866
def get_option(self, name, section=None, default=None):
944
867
self.branch.lock_read()
946
return self._config.get_option(name, section, default)
869
obj = self._get_config()
871
if section is not None:
948
877
self.branch.unlock()
950
880
def set_option(self, value, name, section=None):
951
881
"""Set a per-branch configuration option"""
952
882
self.branch.lock_write()
954
self._config.set_option(value, name, section)
884
cfg_obj = self._get_config()
889
obj = cfg_obj[section]
891
cfg_obj[section] = {}
892
obj = cfg_obj[section]
894
out_file = StringIO()
895
cfg_obj.write(out_file)
897
self.branch.control_files.put('branch.conf', out_file)
956
899
self.branch.unlock()
959
class AuthenticationConfig(object):
960
"""The authentication configuration file based on a ini file.
962
Implements the authentication.conf file described in
963
doc/developers/authentication-ring.txt.
966
def __init__(self, _file=None):
967
self._config = None # The ConfigObj
969
self._filename = authentication_config_filename()
970
self._input = self._filename = authentication_config_filename()
972
# Tests can provide a string as _file
973
self._filename = None
976
def _get_config(self):
977
if self._config is not None:
980
# FIXME: Should we validate something here ? Includes: empty
981
# sections are useless, at least one of
982
# user/password/password_encoding should be defined, etc.
984
# Note: the encoding below declares that the file itself is utf-8
985
# encoded, but the values in the ConfigObj are always Unicode.
986
self._config = ConfigObj(self._input, encoding='utf-8')
987
except configobj.ConfigObjError, e:
988
raise errors.ParseConfigError(e.errors, e.config.filename)
992
"""Save the config file, only tests should use it for now."""
993
conf_dir = os.path.dirname(self._filename)
994
ensure_config_dir_exists(conf_dir)
995
f = file(self._filename, 'wb')
997
self._get_config().write(f)
1001
def _set_option(self, section_name, option_name, value):
1002
"""Set an authentication configuration option"""
1003
conf = self._get_config()
1004
section = conf.get(section_name)
1007
section = conf[section]
1008
section[option_name] = value
1011
def get_credentials(self, scheme, host, port=None, user=None, path=None,
1013
"""Returns the matching credentials from authentication.conf file.
1015
:param scheme: protocol
1017
:param host: the server address
1019
:param port: the associated port (optional)
1021
:param user: login (optional)
1023
:param path: the absolute path on the server (optional)
1025
:param realm: the http authentication realm (optional)
1027
:return: A dict containing the matching credentials or None.
1029
- name: the section name of the credentials in the
1030
authentication.conf file,
1031
- user: can't be different from the provided user if any,
1032
- scheme: the server protocol,
1033
- host: the server address,
1034
- port: the server port (can be None),
1035
- path: the absolute server path (can be None),
1036
- realm: the http specific authentication realm (can be None),
1037
- password: the decoded password, could be None if the credential
1038
defines only the user
1039
- verify_certificates: https specific, True if the server
1040
certificate should be verified, False otherwise.
1043
for auth_def_name, auth_def in self._get_config().items():
1044
if type(auth_def) is not configobj.Section:
1045
raise ValueError("%s defined outside a section" % auth_def_name)
1047
a_scheme, a_host, a_user, a_path = map(
1048
auth_def.get, ['scheme', 'host', 'user', 'path'])
1051
a_port = auth_def.as_int('port')
1055
raise ValueError("'port' not numeric in %s" % auth_def_name)
1057
a_verify_certificates = auth_def.as_bool('verify_certificates')
1059
a_verify_certificates = True
1062
"'verify_certificates' not boolean in %s" % auth_def_name)
1065
if a_scheme is not None and scheme != a_scheme:
1067
if a_host is not None:
1068
if not (host == a_host
1069
or (a_host.startswith('.') and host.endswith(a_host))):
1071
if a_port is not None and port != a_port:
1073
if (a_path is not None and path is not None
1074
and not path.startswith(a_path)):
1076
if (a_user is not None and user is not None
1077
and a_user != user):
1078
# Never contradict the caller about the user to be used
1083
# Prepare a credentials dictionary with additional keys
1084
# for the credential providers
1085
credentials = dict(name=auth_def_name,
1092
password=auth_def.get('password', None),
1093
verify_certificates=a_verify_certificates)
1094
# Decode the password in the credentials (or get one)
1095
self.decode_password(credentials,
1096
auth_def.get('password_encoding', None))
1097
if 'auth' in debug.debug_flags:
1098
trace.mutter("Using authentication section: %r", auth_def_name)
1101
if credentials is None:
1102
# No credentials were found in authentication.conf, try the fallback
1103
# credentials stores.
1104
credentials = credential_store_registry.get_fallback_credentials(
1105
scheme, host, port, user, path, realm)
1109
def set_credentials(self, name, host, user, scheme=None, password=None,
1110
port=None, path=None, verify_certificates=None,
1112
"""Set authentication credentials for a host.
1114
Any existing credentials with matching scheme, host, port and path
1115
will be deleted, regardless of name.
1117
:param name: An arbitrary name to describe this set of credentials.
1118
:param host: Name of the host that accepts these credentials.
1119
:param user: The username portion of these credentials.
1120
:param scheme: The URL scheme (e.g. ssh, http) the credentials apply
1122
:param password: Password portion of these credentials.
1123
:param port: The IP port on the host that these credentials apply to.
1124
:param path: A filesystem path on the host that these credentials
1126
:param verify_certificates: On https, verify server certificates if
1128
:param realm: The http authentication realm (optional).
1130
values = {'host': host, 'user': user}
1131
if password is not None:
1132
values['password'] = password
1133
if scheme is not None:
1134
values['scheme'] = scheme
1135
if port is not None:
1136
values['port'] = '%d' % port
1137
if path is not None:
1138
values['path'] = path
1139
if verify_certificates is not None:
1140
values['verify_certificates'] = str(verify_certificates)
1141
if realm is not None:
1142
values['realm'] = realm
1143
config = self._get_config()
1145
for section, existing_values in config.items():
1146
for key in ('scheme', 'host', 'port', 'path', 'realm'):
1147
if existing_values.get(key) != values.get(key):
1151
config.update({name: values})
1154
def get_user(self, scheme, host, port=None, realm=None, path=None,
1155
prompt=None, ask=False, default=None):
1156
"""Get a user from authentication file.
1158
:param scheme: protocol
1160
:param host: the server address
1162
:param port: the associated port (optional)
1164
:param realm: the realm sent by the server (optional)
1166
:param path: the absolute path on the server (optional)
1168
:param ask: Ask the user if there is no explicitly configured username
1171
:param default: The username returned if none is defined (optional).
1173
:return: The found user.
1175
credentials = self.get_credentials(scheme, host, port, user=None,
1176
path=path, realm=realm)
1177
if credentials is not None:
1178
user = credentials['user']
1184
# Create a default prompt suitable for most cases
1185
prompt = scheme.upper() + ' %(host)s username'
1186
# Special handling for optional fields in the prompt
1187
if port is not None:
1188
prompt_host = '%s:%d' % (host, port)
1191
user = ui.ui_factory.get_username(prompt, host=prompt_host)
1196
def get_password(self, scheme, host, user, port=None,
1197
realm=None, path=None, prompt=None):
1198
"""Get a password from authentication file or prompt the user for one.
1200
:param scheme: protocol
1202
:param host: the server address
1204
:param port: the associated port (optional)
1208
:param realm: the realm sent by the server (optional)
1210
:param path: the absolute path on the server (optional)
1212
:return: The found password or the one entered by the user.
1214
credentials = self.get_credentials(scheme, host, port, user, path,
1216
if credentials is not None:
1217
password = credentials['password']
1218
if password is not None and scheme is 'ssh':
1219
trace.warning('password ignored in section [%s],'
1220
' use an ssh agent instead'
1221
% credentials['name'])
1225
# Prompt user only if we could't find a password
1226
if password is None:
1228
# Create a default prompt suitable for most cases
1229
prompt = '%s' % scheme.upper() + ' %(user)s@%(host)s password'
1230
# Special handling for optional fields in the prompt
1231
if port is not None:
1232
prompt_host = '%s:%d' % (host, port)
1235
password = ui.ui_factory.get_password(prompt,
1236
host=prompt_host, user=user)
1239
def decode_password(self, credentials, encoding):
1241
cs = credential_store_registry.get_credential_store(encoding)
1243
raise ValueError('%r is not a known password_encoding' % encoding)
1244
credentials['password'] = cs.decode_password(credentials)
1248
class CredentialStoreRegistry(registry.Registry):
1249
"""A class that registers credential stores.
1251
A credential store provides access to credentials via the password_encoding
1252
field in authentication.conf sections.
1254
Except for stores provided by bzr itself, most stores are expected to be
1255
provided by plugins that will therefore use
1256
register_lazy(password_encoding, module_name, member_name, help=help,
1257
fallback=fallback) to install themselves.
1259
A fallback credential store is one that is queried if no credentials can be
1260
found via authentication.conf.
1263
def get_credential_store(self, encoding=None):
1264
cs = self.get(encoding)
1269
def is_fallback(self, name):
1270
"""Check if the named credentials store should be used as fallback."""
1271
return self.get_info(name)
1273
def get_fallback_credentials(self, scheme, host, port=None, user=None,
1274
path=None, realm=None):
1275
"""Request credentials from all fallback credentials stores.
1277
The first credentials store that can provide credentials wins.
1280
for name in self.keys():
1281
if not self.is_fallback(name):
1283
cs = self.get_credential_store(name)
1284
credentials = cs.get_credentials(scheme, host, port, user,
1286
if credentials is not None:
1287
# We found some credentials
1291
def register(self, key, obj, help=None, override_existing=False,
1293
"""Register a new object to a name.
1295
:param key: This is the key to use to request the object later.
1296
:param obj: The object to register.
1297
:param help: Help text for this entry. This may be a string or
1298
a callable. If it is a callable, it should take two
1299
parameters (registry, key): this registry and the key that
1300
the help was registered under.
1301
:param override_existing: Raise KeyErorr if False and something has
1302
already been registered for that key. If True, ignore if there
1303
is an existing key (always register the new value).
1304
:param fallback: Whether this credential store should be
1307
return super(CredentialStoreRegistry,
1308
self).register(key, obj, help, info=fallback,
1309
override_existing=override_existing)
1311
def register_lazy(self, key, module_name, member_name,
1312
help=None, override_existing=False,
1314
"""Register a new credential store to be loaded on request.
1316
:param module_name: The python path to the module. Such as 'os.path'.
1317
:param member_name: The member of the module to return. If empty or
1318
None, get() will return the module itself.
1319
:param help: Help text for this entry. This may be a string or
1321
:param override_existing: If True, replace the existing object
1322
with the new one. If False, if there is already something
1323
registered with the same key, raise a KeyError
1324
:param fallback: Whether this credential store should be
1327
return super(CredentialStoreRegistry, self).register_lazy(
1328
key, module_name, member_name, help,
1329
info=fallback, override_existing=override_existing)
1332
credential_store_registry = CredentialStoreRegistry()
1335
class CredentialStore(object):
1336
"""An abstract class to implement storage for credentials"""
1338
def decode_password(self, credentials):
1339
"""Returns a clear text password for the provided credentials."""
1340
raise NotImplementedError(self.decode_password)
1342
def get_credentials(self, scheme, host, port=None, user=None, path=None,
1344
"""Return the matching credentials from this credential store.
1346
This method is only called on fallback credential stores.
1348
raise NotImplementedError(self.get_credentials)
1352
class PlainTextCredentialStore(CredentialStore):
1353
__doc__ = """Plain text credential store for the authentication.conf file"""
1355
def decode_password(self, credentials):
1356
"""See CredentialStore.decode_password."""
1357
return credentials['password']
1360
credential_store_registry.register('plain', PlainTextCredentialStore,
1361
help=PlainTextCredentialStore.__doc__)
1362
credential_store_registry.default_key = 'plain'
1365
class BzrDirConfig(object):
1367
def __init__(self, bzrdir):
1368
self._bzrdir = bzrdir
1369
self._config = bzrdir._get_config()
1371
def set_default_stack_on(self, value):
1372
"""Set the default stacking location.
1374
It may be set to a location, or None.
1376
This policy affects all branches contained by this bzrdir, except for
1377
those under repositories.
1379
if self._config is None:
1380
raise errors.BzrError("Cannot set configuration in %s" % self._bzrdir)
1382
self._config.set_option('', 'default_stack_on')
1384
self._config.set_option(value, 'default_stack_on')
1386
def get_default_stack_on(self):
1387
"""Return the default stacking location.
1389
This will either be a location, or None.
1391
This policy affects all branches contained by this bzrdir, except for
1392
those under repositories.
1394
if self._config is None:
1396
value = self._config.get_option('default_stack_on')
1402
class TransportConfig(object):
1403
"""A Config that reads/writes a config file on a Transport.
1405
It is a low-level object that considers config data to be name/value pairs
1406
that may be associated with a section. Assigning meaning to the these
1407
values is done at higher levels like TreeConfig.
1410
def __init__(self, transport, filename):
1411
self._transport = transport
1412
self._filename = filename
1414
def get_option(self, name, section=None, default=None):
1415
"""Return the value associated with a named option.
1417
:param name: The name of the value
1418
:param section: The section the option is in (if any)
1419
:param default: The value to return if the value is not set
1420
:return: The value or default value
1422
configobj = self._get_configobj()
1424
section_obj = configobj
1427
section_obj = configobj[section]
1430
return section_obj.get(name, default)
1432
def set_option(self, value, name, section=None):
1433
"""Set the value associated with a named option.
1435
:param value: The value to set
1436
:param name: The name of the value to set
1437
:param section: The section the option is in (if any)
1439
configobj = self._get_configobj()
1441
configobj[name] = value
1443
configobj.setdefault(section, {})[name] = value
1444
self._set_configobj(configobj)
1446
def _get_config_file(self):
1448
return StringIO(self._transport.get_bytes(self._filename))
1449
except errors.NoSuchFile:
1452
def _get_configobj(self):
1453
f = self._get_config_file()
1455
return ConfigObj(f, encoding='utf-8')
1459
def _set_configobj(self, configobj):
1460
out_file = StringIO()
1461
configobj.write(out_file)
1463
self._transport.put_file(self._filename, out_file)