def _authenticateApiKey(self, username, password):
        if not Setting().get(SettingKey.API_KEYS):
            logger.warn('API key functionality is disabled')
            return False

        token_user, token = ApiKeyModel().createToken(password[4:], days=7)
        user = self._getUser(username)
        return token_user.get('_id', 'no_token') == user['_id']
Esempio n. 2
0
def migrate(user, apiUrl):
    print("\nMigrating data for user %s" % user['login'])

    # Get or create API key for migration
    apiKey = ApiKey().createApiKey(user, 'migration')

    # Look up the "Home" directory
    homeDir = lookUpPath("/user/%s/Home" % user['login'], user=user,
                         test=True)["document"]
    print("Found homeDir %s" % homeDir)

    # Remove old Home, create new (needed for wt_home_dirs)
    print("Removing homeDir")
    Folder().remove(homeDir)
    print("Creating new homeDir")
    newHomeDir = Folder().createFolder(parent=user,
                                       name="Home",
                                       creator=user,
                                       parentType="user")

    # Mount home dir via webdav
    tmpDir = "/tmp/migrate/%s/" % user['login']
    os.makedirs(tmpDir, exist_ok=True)
    print("Created tmpDir %s" % tmpDir)

    mount(apiKey['key'], tmpDir, newHomeDir['_id'], apiUrl)

    # Move Data directory, if present
    print("Moving files")
    try:
        if os.path.exists('/user/%s/Data' % user['login']):
            shutil.move('/user/%s/Data' % user['login'], tmpDir)
        if os.path.exists('/user/%s/Workspace' % user['login']):
            shutil.move('/user/%s/Workspace' % user['login'], tmpDir)
        if os.path.exists('/user/%s/Home' % user['login']):
            for file in glob.glob('/user/%s/Home/*' % user['login']):
                print(file)
                shutil.move(file, tmpDir)
            os.rmdir('/user/%s/Home' % user['login'])
    except Exception as e:
        print("Error moving files: %s" % str(e))

    time.sleep(60)

    # Unmount
    unmount(tmpDir)

    # Remove tmp folder
    shutil.rmtree(tmpDir)

    # Remove the API key
    ApiKey().remove(apiKey)
Esempio n. 3
0
    def testScopeValidation(self):
        # Make sure normal user cannot request admin scopes
        requestedScopes = [TokenScope.DATA_OWN, TokenScope.SETTINGS_READ]
        msg = 'Invalid scopes: %s.$' % TokenScope.SETTINGS_READ

        with six.assertRaisesRegex(self, ValidationException, msg):
            ApiKey().createApiKey(user=self.user, name='', scope=requestedScopes)

        # Make sure an unregistered scope cannot be set on an API key
        requestedScopes = [TokenScope.DATA_OWN, TokenScope.SETTINGS_READ, 'nonsense']
        msg = 'Invalid scopes: nonsense.$'
        with six.assertRaisesRegex(self, ValidationException, msg):
            ApiKey().createApiKey(user=self.admin, name='', scope=requestedScopes)
Esempio n. 4
0
def testReactivatedKeyCanCreateTokens(server, user, apiKey):
    newScopes = [TokenScope.DATA_READ, TokenScope.DATA_WRITE]
    resp = server.request('/api_key/%s' % apiKey['_id'],
                          params={
                              'active': False,
                              'tokenDuration': 10,
                              'scope': json.dumps(newScopes)
                          },
                          method='PUT',
                          user=user)
    assertStatusOk(resp)

    resp = server.request('/api_key/%s' % apiKey['_id'],
                          params={'active': True},
                          method='PUT',
                          user=user)
    assertStatusOk(resp)
    assert resp.json['key'] == apiKey['key']
    apiKey = ApiKey().load(resp.json['_id'], force=True)

    # Should now be able to make tokens with 10 day duration
    resp = server.request('/api_key/token',
                          method='POST',
                          params={'key': apiKey['key']})
    assertStatusOk(resp)
    token = Token().load(resp.json['authToken']['token'],
                         force=True,
                         objectId=False)
    duration = token['expires'] - token['created']
    assert duration == datetime.timedelta(days=10)
    assert set(token['scope']) == set(newScopes)
Esempio n. 5
0
def testScopeValidation(db, admin, user):
    # Make sure normal user cannot request admin scopes
    requestedScopes = [TokenScope.DATA_OWN, TokenScope.SETTINGS_READ]

    with pytest.raises(ValidationException,
                       match='Invalid scopes: %s.$' %
                       TokenScope.SETTINGS_READ):
        ApiKey().createApiKey(user=user, name='', scope=requestedScopes)

    # Make sure an unregistered scope cannot be set on an API key
    requestedScopes = [
        TokenScope.DATA_OWN, TokenScope.SETTINGS_READ, 'nonsense'
    ]

    with pytest.raises(ValidationException,
                       match='Invalid scopes: nonsense.$'):
        ApiKey().createApiKey(user=admin, name='', scope=requestedScopes)
Esempio n. 6
0
def apiKey(server, user):
    # Create a new API key with full access
    resp = server.request('/api_key',
                          method='POST',
                          params={'name': 'test key'},
                          user=user)
    assertStatusOk(resp)
    apiKey = ApiKey().load(resp.json['_id'], force=True)

    yield apiKey
Esempio n. 7
0
    def setUp(self):
        base.TestCase.setUp(self)

        self.user = User().createUser(
            firstName='First', lastName='Last', login='******',
            password='******', email='*****@*****.**')
        self.publicFolder = six.next(Folder().childFolders(
            parentType='user', parent=self.user, user=None, limit=1))
        self.apiKey = ApiKey().createApiKey(self.user, name='')

        self.downloadDir = os.path.join(
            os.path.dirname(__file__), '_testDownload')
        shutil.rmtree(self.downloadDir, ignore_errors=True)
Esempio n. 8
0
def testDisableApiKeysSetting(server, user):
    errMsg = 'API key functionality is disabled on this instance.'

    resp = server.request('/api_key',
                          method='POST',
                          user=user,
                          params={'name': 'test key'})
    assertStatusOk(resp)

    # Disable API keys
    Setting().set(SettingKey.API_KEYS, False)

    # Key should still exist
    key = ApiKey().load(resp.json['_id'], force=True, exc=True)

    # No longer possible to authenticate with existing key
    resp = server.request('/api_key/token',
                          method='POST',
                          params={'key': key['key']})
    assertStatus(resp, 400)
    assert resp.json['message'] == errMsg

    # No longer possible to create new keys
    resp = server.request('/api_key',
                          method='POST',
                          user=user,
                          params={'name': 'should not work'})
    assertStatus(resp, 400)
    assert resp.json['message'] == errMsg

    # Still possible to delete key
    resp = server.request('/api_key/%s' % key['_id'],
                          method='DELETE',
                          user=user)
    assertStatusOk(resp)
    assert ApiKey().load(key['_id'], force=True) is None
Esempio n. 9
0
def testInactiveKeyStructure(server, user, apiKey):
    newScopes = [TokenScope.DATA_READ, TokenScope.DATA_WRITE]
    resp = server.request('/api_key/%s' % apiKey['_id'],
                          params={
                              'active': False,
                              'tokenDuration': 10,
                              'scope': json.dumps(newScopes)
                          },
                          method='PUT',
                          user=user)
    assertStatusOk(resp)

    # Make sure key itself didn't change
    assert resp.json['key'] == apiKey['key']
    apiKey = ApiKey().load(resp.json['_id'], force=True)
    assert not apiKey['active']
    assert apiKey['tokenDuration'] == 10
    assert set(apiKey['scope']) == set(newScopes)
Esempio n. 10
0
    def setUp(self):
        super().setUp(self)
        from girder.plugins.wt_home_dir import HOME_DIRS_APPS
        self.homeDirsApps = HOME_DIRS_APPS  # nopep8
        from girder.plugins.wt_home_dir.constants import WORKSPACE_NAME
        global WORKSPACE_NAME
        # We need to recreate DirectFS assetstore, which was dropped in
        # base.TestCase.setUp...

        # girder.plugins is not available until setUp is running
        self.rootPaths = {}
        for e in self.homeDirsApps.entries():
            provider = e.app.providerMap['/']['provider']
            self.rootPaths[e.realm] = provider.rootFolderPath
            if e.realm == 'homes':
                self.homesRoot = provider.rootFolderPath
                self.homesPathMapper = e.pathMapper

        users = ({
            'email': '*****@*****.**',
            'login': '******',
            'firstName': 'Root',
            'lastName': 'van Klompf',
            'password': '******'
        }, {
            'email': '*****@*****.**',
            'login': '******',
            'firstName': 'Joe',
            'lastName': 'Regular',
            'password': '******'
        })
        self.admin, self.user = [
            self.model('user').createUser(**user) for user in users
        ]
        self.token = Token().createToken(self.user)
        self.api_key = ApiKey().createApiKey(user=self.user,
                                             name="webdav",
                                             scope=[TokenScope.DATA_OWN])

        from girder.plugins.wt_versioning.constants import PluginSettings as \
            VerPluginSettings
        Setting().set(VerPluginSettings.RUNS_DIRS_ROOT, self.rootPaths["runs"])
        # Needs to be on the same level as runs and needs to be called versions...
        version_root = pathlib.Path(os.path.dirname(
            self.rootPaths["runs"])) / "versions"
        if not version_root.is_dir():
            version_root.mkdir()
        Setting().set(VerPluginSettings.VERSIONS_DIRS_ROOT,
                      version_root.as_posix())

        from girder.plugins.wholetale.models.image import Image
        from girder.plugins.wholetale.models.tale import Tale
        image = Image().createImage(name='test image',
                                    creator=self.admin,
                                    public=True)
        self.privateTale = Tale().createTale(image, [],
                                             creator=self.user,
                                             public=False)
        # TODO: add tests checking that other users only have read access to public tales
        self.publicTale = Tale().createTale(image, [],
                                            creator=self.user,
                                            public=True)
        self.clearDAVAuthCache()
Esempio n. 11
0
    def testKeyPolicies(self):
        # Create a new API key with full access
        resp = self.request('/api_key', method='POST', params={
            'name': 'test key'
        }, user=self.user)
        self.assertStatusOk(resp)
        apiKey = ApiKey().load(resp.json['_id'], force=True)
        self.assertEqual(apiKey['scope'], None)
        self.assertEqual(apiKey['name'], 'test key')
        self.assertEqual(apiKey['lastUse'], None)
        self.assertEqual(apiKey['tokenDuration'], None)
        self.assertEqual(apiKey['active'], True)

        # Create a token using the key
        resp = self.request('/api_key/token', method='POST', params={
            'key': apiKey['key'],
            'duration': self.defaultDuration + 1000
        })
        self.assertStatusOk(resp)
        token = Token().load(resp.json['authToken']['token'], force=True, objectId=False)
        # Make sure token has full user auth access
        self.assertEqual(token['userId'], self.user['_id'])
        self.assertEqual(token['scope'], [TokenScope.USER_AUTH])
        # Make sure the token references the API key used to create it
        self.assertEqual(token['apiKeyId'], apiKey['_id'])

        # Make sure the token duration is not longer than the default
        duration = token['expires'] - token['created']
        self.assertEqual(duration, datetime.timedelta(days=self.defaultDuration))

        # We should be able to request a duration shorter than default
        resp = self.request('/api_key/token', method='POST', params={
            'key': apiKey['key'],
            'duration': self.defaultDuration - 1
        })
        self.assertStatusOk(resp)
        token = Token().load(resp.json['authToken']['token'], force=True, objectId=False)
        duration = token['expires'] - token['created']
        self.assertEqual(duration, datetime.timedelta(days=self.defaultDuration - 1))

        # We should have two tokens for this key
        q = {
            'userId': self.user['_id'],
            'apiKeyId': apiKey['_id']
        }
        count = Token().find(q).count()
        self.assertEqual(count, 2)

        # Deactivate the key and change the token duration and scope
        newScopes = [TokenScope.DATA_READ, TokenScope.DATA_WRITE]
        resp = self.request('/api_key/%s' % apiKey['_id'], params={
            'active': False,
            'tokenDuration': 10,
            'scope': json.dumps(newScopes)
        }, method='PUT', user=self.user)
        self.assertStatusOk(resp)
        # Make sure key itself didn't change
        self.assertEqual(resp.json['key'], apiKey['key'])
        apiKey = ApiKey().load(resp.json['_id'], force=True)
        self.assertEqual(apiKey['active'], False)
        self.assertEqual(apiKey['tokenDuration'], 10)
        self.assertEqual(set(apiKey['scope']), set(newScopes))
        # Should now have a last used timestamp
        self.assertIsInstance(apiKey['lastUse'], datetime.datetime)

        # This should have deleted all corresponding tokens
        q = {
            'userId': self.user['_id'],
            'apiKeyId': apiKey['_id']
        }
        count = Token().find(q).count()
        self.assertEqual(count, 0)

        # We should not be able to create tokens for this key anymore
        resp = self.request('/api_key/token', method='POST', params={
            'key': apiKey['key']
        })
        self.assertStatus(resp, 400)
        self.assertEqual(resp.json['message'], 'Invalid API key.')

        # Reactivate key
        resp = self.request('/api_key/%s' % apiKey['_id'], params={
            'active': True
        }, method='PUT', user=self.user)
        self.assertStatusOk(resp)
        self.assertEqual(resp.json['key'], apiKey['key'])
        apiKey = ApiKey().load(resp.json['_id'], force=True)

        # Should now be able to make tokens with 10 day duration
        resp = self.request('/api_key/token', method='POST', params={
            'key': apiKey['key']
        })
        self.assertStatusOk(resp)
        token = Token().load(resp.json['authToken']['token'], force=True, objectId=False)
        duration = token['expires'] - token['created']
        self.assertEqual(duration, datetime.timedelta(days=10))
        self.assertEqual(set(token['scope']), set(newScopes))

        # Deleting the API key should delete the tokens made with it
        count = Token().find(q).count()
        self.assertEqual(count, 1)
        resp = self.request('/api_key/%s' % apiKey['_id'], method='DELETE', user=self.user)
        self.assertStatusOk(resp)
        count = Token().find(q).count()
        self.assertEqual(count, 0)