Do not allow credentials files to be symlinks.
Reviewed in https://codereview.appspot.com/6476062/.
diff --git a/oauth2client/file.py b/oauth2client/file.py
index 1abc6d2..1895f94 100644
--- a/oauth2client/file.py
+++ b/oauth2client/file.py
@@ -29,6 +29,10 @@
from client import Credentials
+class CredentialsFileSymbolicLinkError(Exception):
+ """Credentials files must not be symbolic links."""
+
+
class Storage(BaseStorage):
"""Store and retrieve a single credential to and from a file."""
@@ -36,6 +40,11 @@
self._filename = filename
self._lock = threading.Lock()
+ def _validate_file(self):
+ if os.path.islink(self._filename):
+ raise CredentialsFileSymbolicLinkError(
+ 'File: %s is a symbolic link.' % self._filename)
+
def acquire_lock(self):
"""Acquires any lock necessary to access this Storage.
@@ -55,8 +64,12 @@
Returns:
oauth2client.client.Credentials
+
+ Raises:
+ CredentialsFileSymbolicLinkError if the file is a symbolic link.
"""
credentials = None
+ self._validate_file()
try:
f = open(self._filename, 'rb')
content = f.read()
@@ -90,9 +103,13 @@
Args:
credentials: Credentials, the credentials to store.
+
+ Raises:
+ CredentialsFileSymbolicLinkError if the file is a symbolic link.
"""
self._create_file_if_needed()
+ self._validate_file()
f = open(self._filename, 'wb')
f.write(credentials.to_json())
f.close()
diff --git a/oauth2client/locked_file.py b/oauth2client/locked_file.py
index 8f35c90..1cfe532 100644
--- a/oauth2client/locked_file.py
+++ b/oauth2client/locked_file.py
@@ -28,11 +28,20 @@
logger = logging.getLogger(__name__)
+class CredentialsFileSymbolicLinkError(Exception):
+ """Credentials files must not be symbolic links."""
+
+
class AlreadyLockedException(Exception):
"""Trying to lock a file that has already been locked by the LockedFile."""
pass
+def validate_file(filename):
+ if os.path.islink(filename):
+ raise CredentialsFileSymbolicLinkError(
+ 'File: %s is a symbolic link.' % filename)
+
class _Opener(object):
"""Base class for different locking primitives."""
@@ -91,12 +100,14 @@
Raises:
AlreadyLockedException: if the lock is already acquired.
IOError: if the open fails.
+ CredentialsFileSymbolicLinkError if the file is a symbolic link.
"""
if self._locked:
raise AlreadyLockedException('File %s is already locked' %
self._filename)
self._locked = False
+ validate_file(self._filename)
try:
self._fh = open(self._filename, self._mode)
except IOError, e:
@@ -159,12 +170,14 @@
Raises:
AlreadyLockedException: if the lock is already acquired.
IOError: if the open fails.
+ CredentialsFileSymbolicLinkError if the file is a symbolic link.
"""
if self._locked:
raise AlreadyLockedException('File %s is already locked' %
self._filename)
start_time = time.time()
+ validate_file(self._filename)
try:
self._fh = open(self._filename, self._mode)
except IOError, e:
@@ -232,12 +245,14 @@
Raises:
AlreadyLockedException: if the lock is already acquired.
IOError: if the open fails.
+ CredentialsFileSymbolicLinkError if the file is a symbolic link.
"""
if self._locked:
raise AlreadyLockedException('File %s is already locked' %
self._filename)
start_time = time.time()
+ validate_file(self._filename)
try:
self._fh = open(self._filename, self._mode)
except IOError, e:
diff --git a/oauth2client/multistore_file.py b/oauth2client/multistore_file.py
index e190c6a..c919573 100644
--- a/oauth2client/multistore_file.py
+++ b/oauth2client/multistore_file.py
@@ -76,7 +76,7 @@
An object derived from client.Storage for getting/setting the
credential.
"""
- filename = os.path.realpath(os.path.expanduser(filename))
+ filename = os.path.expanduser(filename)
_multistores_lock.acquire()
try:
multistore = _multistores.setdefault(