Raise Error Code 008 for invalid CRLs

This commit is contained in:
Montana 2019-03-12 16:42:58 -04:00
parent d6906c8504
commit effec85cf9
5 changed files with 29 additions and 10 deletions

View File

@ -47,8 +47,6 @@ class AuthenticationContext:
def _crl_check(self): def _crl_check(self):
try: try:
self.crl_cache.crl_check(self.cert) self.crl_cache.crl_check(self.cert)
except CRLInvalidException as exc:
raise UnauthenticatedError("CRL expired. " + str(exc))
except CRLRevocationException as exc: except CRLRevocationException as exc:
raise UnauthenticatedError("CRL check failed. " + str(exc)) raise UnauthenticatedError("CRL check failed. " + str(exc))

View File

@ -2,9 +2,13 @@ import sys
import os import os
import re import re
import hashlib import hashlib
from flask import current_app as app
from datetime import datetime from datetime import datetime
from OpenSSL import crypto, SSL from OpenSSL import crypto, SSL
# error codes from OpenSSL: https://github.com/openssl/openssl/blob/2c75f03b39de2fa7d006bc0f0d7c58235a54d9bb/include/openssl/x509_vfy.h#L111
CRL_EXPIRED_ERROR_CODE = 12
def get_common_name(x509_name_object): def get_common_name(x509_name_object):
for comp in x509_name_object.get_components(): for comp in x509_name_object.get_components():
@ -176,10 +180,11 @@ class CRLCache(CRLInterface):
return True return True
except crypto.X509StoreContextError as err: except crypto.X509StoreContextError as err:
if ( if err.args[0][0] == CRL_EXPIRED_ERROR_CODE:
err.args[0][2] == "CRL has expired" if app.config.get("CRL_FAIL_OPEN"):
): # there has to be a better way than this return True
raise CRLInvalidException("CRL expired. Args: {}".format(err.args)) else:
raise CRLInvalidException("CRL expired. Args: {}".format(err.args))
raise CRLRevocationException( raise CRLRevocationException(
"Certificate revoked or errored. Error: {}. Args: {}".format( "Certificate revoked or errored. Error: {}. Args: {}".format(
type(err), err.args type(err), err.args

View File

@ -8,6 +8,7 @@ from atst.domain.invitations import (
ExpiredError as InvitationExpiredError, ExpiredError as InvitationExpiredError,
WrongUserError as InvitationWrongUserError, WrongUserError as InvitationWrongUserError,
) )
from atst.domain.authnid.crl import CRLInvalidException
from atst.domain.portfolios import PortfolioError from atst.domain.portfolios import PortfolioError
from atst.utils.flash import formatted_flash as flash from atst.utils.flash import formatted_flash as flash
@ -32,6 +33,11 @@ def make_error_pages(app):
def not_found(e): def not_found(e):
return handle_error(e) return handle_error(e)
@app.errorhandler(CRLInvalidException)
# pylint: disable=unused-variable
def missing_crl(e):
return handle_error(e, message="Error Code 008", code=401)
@app.errorhandler(exceptions.UnauthenticatedError) @app.errorhandler(exceptions.UnauthenticatedError)
# pylint: disable=unused-variable # pylint: disable=unused-variable
def unauthorized(e): def unauthorized(e):

View File

@ -56,12 +56,9 @@ def test_expired_crl_check_fails():
auth_context = AuthenticationContext( auth_context = AuthenticationContext(
MockCRLCache(valid=False, expired=True), "SUCCESS", DOD_SDN, CERT MockCRLCache(valid=False, expired=True), "SUCCESS", DOD_SDN, CERT
) )
with pytest.raises(UnauthenticatedError) as excinfo: with pytest.raises(CRLInvalidException) as excinfo:
assert auth_context.authenticate() assert auth_context.authenticate()
(message,) = excinfo.value.args
assert "CRL expired" in message
def test_bad_sdn(): def test_bad_sdn():
auth_context = AuthenticationContext(MockCRLCache(), "SUCCESS", "abc123", CERT) auth_context = AuthenticationContext(MockCRLCache(), "SUCCESS", "abc123", CERT)

View File

@ -6,6 +6,7 @@ from .mocks import DOD_SDN_INFO, DOD_SDN, FIXTURE_EMAIL_ADDRESS
from atst.domain.users import Users from atst.domain.users import Users
from atst.domain.roles import Roles from atst.domain.roles import Roles
from atst.domain.exceptions import NotFoundError from atst.domain.exceptions import NotFoundError
from atst.domain.authnid.crl import CRLInvalidException
from atst.domain.auth import UNPROTECTED_ROUTES from atst.domain.auth import UNPROTECTED_ROUTES
from .factories import UserFactory from .factories import UserFactory
@ -211,3 +212,15 @@ def test_redirected_on_login(client, monkeypatch):
target_route = url_for("users.user") target_route = url_for("users.user")
response = _login(client, next=target_route) response = _login(client, next=target_route)
assert target_route in response.headers.get("Location") assert target_route in response.headers.get("Location")
def test_error_on_invalid_crl(client, monkeypatch):
def _raise_crl_error(*args):
raise CRLInvalidException()
monkeypatch.setattr(
"atst.domain.authnid.AuthenticationContext.authenticate", _raise_crl_error
)
response = _login(client)
assert response.status_code == 401
assert "Error Code 008" in response.data.decode()