def revoke_application(request):
    assert_authenticated_user_is_registered(request)

    try:
        app_id = bson.ObjectId(request.matchdict['app'])
    except bson.errors.InvalidId:
        return HTTPBadRequest(body='Invalid application id')

    app = request.db.applications.find_one(app_id)
    if app is None:
        return HTTPNotFound()

    authorizator = Authorizator(request.db, app)

    if not authorizator.is_app_authorized(request.user):
        return HTTPUnauthorized()

    if 'submit' in request.POST:
        authorizator.remove_user_authorization(request.user)

        request.session.flash(
            _('The access to application ${app} has been revoked',
              mapping={'app': app['name']}),
            'success',
            )
        return HTTPFound(
            location=request.route_path('oauth2_authorized_applications'))

    return {'app': app}
    def test_authorizator(self):
        app = {"_id": "app1"}
        authorizator = Authorizator(self.db, app)
        self.assertTrue(isinstance(authorizator.auth_codes, AuthorizationCodes))
        self.assertTrue(isinstance(authorizator.access_codes, AccessCodes))
        user = {"name": "John Doe", "authorized_apps": []}
        self.db.users.insert(user, safe=True)

        self.assertFalse(authorizator.is_app_authorized(user))

        authorizator.store_user_authorization(user)
        user = self.db.users.find_one({"name": "John Doe"})

        self.assertTrue(authorizator.is_app_authorized(user))
        self.assertEqual(user["authorized_apps"], ["app1"])

        authorizator.remove_user_authorization(user)
        user = self.db.users.find_one({"name": "John Doe"})

        self.assertFalse(authorizator.is_app_authorized(user))
        self.assertFalse("app1" in user["authorized_apps"])
    def test_authorizator(self):
        app = {'_id': 'app1'}
        authorizator = Authorizator(self.db, app)
        self.assertTrue(isinstance(authorizator.auth_codes,
                                   AuthorizationCodes))
        self.assertTrue(isinstance(authorizator.access_codes,
                                   AccessCodes))
        user = {'name': 'John Doe', 'authorized_apps': []}
        self.db.users.insert(user, safe=True)

        self.assertFalse(authorizator.is_app_authorized(user))

        authorizator.store_user_authorization(user)
        user = self.db.users.find_one({'name': 'John Doe'})

        self.assertTrue(authorizator.is_app_authorized(user))
        self.assertEqual(user['authorized_apps'], ['app1'])

        authorizator.remove_user_authorization(user)
        user = self.db.users.find_one({'name': 'John Doe'})

        self.assertFalse(authorizator.is_app_authorized(user))
        self.assertFalse('app1' in user['authorized_apps'])
class AuthorizatorTests(testing.TestCase):

    def setUp(self):
        super(AuthorizatorTests, self).setUp()
        self.authorizator = Authorizator(self.db)

    def test_is_app_authorized_no_authorized_apps(self):
        self.assertFalse(self.authorizator.is_app_authorized([
            'scope1', 'scope2',
        ], {
            'client_id': 1,
            'user': {'_id': 1},
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
        }))

    def test_is_app_authorized_different_client_id(self):
        self.db.authorized_apps.insert({
            'client_id': 1,
            'user': 1,
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
            'scope': 'scope1 scope2',
        })
        self.assertFalse(self.authorizator.is_app_authorized([
            'scope1', 'scope2',
        ], {
            'client_id': 2,
            'user': {'_id': 1},
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
        }))

    def test_is_app_authorized_different_user(self):
        self.db.authorized_apps.insert({
            'client_id': 1,
            'user': 1,
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
            'scope': 'scope1 scope2',
        })
        self.assertFalse(self.authorizator.is_app_authorized([
            'scope1', 'scope2',
        ], {
            'client_id': 1,
            'user': {'_id': 2},
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
        }))

    def test_is_app_authorized_different_redirect_uri(self):
        self.db.authorized_apps.insert({
            'client_id': 1,
            'user': 1,
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
            'scope': 'scope1 scope2',
        })
        self.assertFalse(self.authorizator.is_app_authorized([
            'scope1', 'scope2',
        ], {
            'client_id': 1,
            'user': {'_id': 1},
            'redirect_uri': 'http://example.com/callback-new',
            'response_type': 'code',
        }))

    def test_is_app_authorized_different_response_type(self):
        self.db.authorized_apps.insert({
            'client_id': 1,
            'user': 1,
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
            'scope': 'scope1 scope2',
        })
        self.assertFalse(self.authorizator.is_app_authorized([
            'scope1', 'scope2',
        ], {
            'client_id': 1,
            'user': {'_id': 1},
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'token',
        }))

    def test_is_app_authorized_different_scopes(self):
        self.db.authorized_apps.insert({
            'client_id': 1,
            'user': 1,
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
            'scope': 'scope1 scope2',
        })
        self.assertFalse(self.authorizator.is_app_authorized([
            'scope1', 'scope2', 'scope3',
        ], {
            'client_id': 1,
            'user': {'_id': 1},
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
        }))

    def test_is_app_authorized_everything_equal(self):
        self.db.authorized_apps.insert({
            'client_id': 1,
            'user': 1,
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
            'scope': 'scope1 scope2',
        })
        self.assertTrue(self.authorizator.is_app_authorized([
            'scope1', 'scope2',
        ], {
            'client_id': 1,
            'user': {'_id': 1},
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
        }))

    def test_store_user_authorization_no_previous_authorization(self):
        self.assertEqual(self.db.authorized_apps.count(), 0)
        self.authorizator.store_user_authorization([
            'scope1', 'scope2',
        ], {
            'client_id': 1,
            'user': {'_id': 1},
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
        })
        self.assertEqual(self.db.authorized_apps.count(), 1)

    def test_store_user_authorization_previous_authorization(self):
        self.assertEqual(self.db.authorized_apps.count(), 0)
        self.authorizator.store_user_authorization([
            'scope1', 'scope2',
        ], {
            'client_id': 1,
            'user': {'_id': 1},
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
        })
        self.assertEqual(self.db.authorized_apps.count(), 1)

        # Store the same authorization again
        self.authorizator.store_user_authorization([
            'scope1', 'scope2',
        ], {
            'client_id': 1,
            'user': {'_id': 1},
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
        })
        # still only one record
        self.assertEqual(self.db.authorized_apps.count(), 1)

    def test_get_user_authorizations_empty(self):
        auths = self.authorizator.get_user_authorizations({'_id': 1})
        self.assertEqual(auths.count(), 0)

    def test_get_user_authorizations_one_authorization(self):
        self.authorizator.store_user_authorization([
            'scope1', 'scope2',
        ], {
            'client_id': 1,
            'user': {'_id': 1},
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
        })
        auths = self.authorizator.get_user_authorizations({'_id': 1})
        self.assertEqual(auths.count(), 1)
        self.assertEqual(auths[0]['client_id'], 1)
        self.assertEqual(auths[0]['redirect_uri'], 'http://example.com/callback')
        self.assertEqual(auths[0]['response_type'], 'code')
        self.assertEqual(auths[0]['scope'], 'scope1 scope2')

    def test_get_user_authorizations_two_authorization(self):
        self.authorizator.store_user_authorization([
            'scope1', 'scope2',
        ], {
            'client_id': 1,
            'user': {'_id': 1},
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
        })
        self.authorizator.store_user_authorization([
            'scope1', 'scope2',
        ], {
            'client_id': 2,
            'user': {'_id': 1},
            'redirect_uri': 'http://example.com/callback2',
            'response_type': 'code',
        })
        self.authorizator.store_user_authorization([
            'scope1', 'scope2',
        ], {
            'client_id': 2,
            'user': {'_id': 2},
            'redirect_uri': 'http://example.com/callback2',
            'response_type': 'code',
        })
        auths = self.authorizator.get_user_authorizations({'_id': 1})
        self.assertEqual(auths.count(), 2)
        self.assertEqual(auths[0]['client_id'], 1)
        self.assertEqual(auths[0]['redirect_uri'], 'http://example.com/callback')
        self.assertEqual(auths[0]['response_type'], 'code')
        self.assertEqual(auths[0]['scope'], 'scope1 scope2')

        self.assertEqual(auths[1]['client_id'], 2)
        self.assertEqual(auths[1]['redirect_uri'], 'http://example.com/callback2')
        self.assertEqual(auths[1]['response_type'], 'code')
        self.assertEqual(auths[1]['scope'], 'scope1 scope2')

    def test_remove_user_authorization(self):
        auths = self.authorizator.get_user_authorizations({'_id': 1})
        self.assertEqual(auths.count(), 0)
        self.authorizator.store_user_authorization([
            'scope1', 'scope2',
        ], {
            'client_id': 1,
            'user': {'_id': 1},
            'redirect_uri': 'http://example.com/callback',
            'response_type': 'code',
        })
        auths = self.authorizator.get_user_authorizations({'_id': 1})
        self.assertEqual(auths.count(), 1)
        self.authorizator.remove_user_authorization({'_id': 1}, 1)
        auths = self.authorizator.get_user_authorizations({'_id': 1})
        self.assertEqual(auths.count(), 0)

    def test_remove_all_user_authorizations(self):
        auths = self.authorizator.get_user_authorizations({'_id': 1})
        self.assertEqual(auths.count(), 0)
        self.authorizator.store_user_authorization([
            'scope1', 'scope2',
        ], {
            'client_id': 1,
            'user': {'_id': 1},
            'redirect_uri': 'http://example.com/callback/1',
            'response_type': 'code',
        })
        self.authorizator.store_user_authorization([
            'scope1', 'scope2',
        ], {
            'client_id': 2,
            'user': {'_id': 1},
            'redirect_uri': 'http://example.com/callback/2',
            'response_type': 'code',
        })
        auths = self.authorizator.get_user_authorizations({'_id': 1})
        self.assertEqual(auths.count(), 2)
        self.authorizator.remove_all_user_authorizations({'_id': 1})
        auths = self.authorizator.get_user_authorizations({'_id': 1})
        self.assertEqual(auths.count(), 0)