Exemple #1
0
 def __init__(self, loop):
     self.loop = loop
     self.signer = itsdangerous.Signer(os.environ['GENREML_SIGNING_TOKEN'])
     self.session_signer = itsdangerous.Signer(
         os.environ['SESSION_SIGNING_TOKEN'])
     self.serializer = itsdangerous.Serializer(
         os.environ['GENREML_SIGNING_TOKEN'])
     self.filestore_directory = "/opt/file_store"
     self.genres = os.environ['GENREML_GENRES'].split('|')
     self.model_hash = os.environ['GENREML_MODEL_HASH']
     self.image_labels_to_title = {
         "image_mel_spectrogram_grayscale_original": "Mel Spectrogram",
         "image_mel_spectrogram_image": "Mel Spectrogram",
         "image_mel_spectrogram_original_color": "Mel Spectrogram",
         "image_chromagram_grayscale_original": "Chromagram",
         "image_chromagram_image": "Chromagram",
         "image_chromagram_original_color": "Chromagram",
         "image_db_spectrogram_grayscale_original": "DB Spectrogram",
         "image_db_spectrogram_image": "DB Spectrogram",
         "image_db_spectrogram_original_color": "DB Spectrogram"
     }
     self.prediction_queue = asyncio.Queue()
     self.spectrograms_queue = asyncio.Queue()
     self.batch_store = dict()
     self.predictor_connections = dict()
     self.spectrogram_connections = dict()
Exemple #2
0
def create_session(response, data=None):
    current_session = get_session()
    if current_session:
        current_session.data.update(data or {})
        current_session.save()
        cookie_value = itsdangerous.Signer(settings.SECRET_KEY).sign(current_session._id)
    else:
        session_id = str(bson.objectid.ObjectId())
        session = Session(_id=session_id, data=data or {})
        session.save()
        cookie_value = itsdangerous.Signer(settings.SECRET_KEY).sign(session_id)
        set_session(session)
    if response is not None:
        response.set_cookie(settings.COOKIE_NAME, value=cookie_value, domain=settings.OSF_COOKIE_DOMAIN)
        return response
def create_signer(secret_key, salt):
    """Create a signer configured how we like it.

    The secret_key should be a cyptographically random key.

    The salt should be specific to intend usage of the signature, but does not
    need to be random. It acts to partition signatures between use cases that
    shared the same secret_key.

    The length of secret_key and salt together should be more than the digest
    size, which for sha256 is 32 bytes.

    See https://itsdangerous.palletsprojects.com/en/2.0.x/concepts/ for more info.

    Ideally, we'd use cryptography for this, but that's a much heavier
    dependency than itsdangerous, which is pure python."""
    value = secret_key
    if salt is not None:
        value += salt
    assert len(
        value.encode("utf8")) > 32, "secret_key+salt needs to be > 32 bytes"
    return itsdangerous.Signer(
        secret_key=secret_key,
        salt=salt,
        key_derivation="hmac",  # would like to use HDKF, but not supported
        digest_method=hashlib.sha256,
    )
Exemple #4
0
def test_login0(client):
    """Test login from orcid."""
    resp = client.get("/login0")
    assert resp.status_code == 401

    u = User.select().where(User.orcid.is_null(False)).first()
    email = u.email
    import itsdangerous
    signature = itsdangerous.Signer(
        client.application.secret_key).get_signature(email).decode()
    auth = email + ':' + signature

    resp = client.get(f"/login0/{auth}")
    assert resp.status_code == 302
    assert current_user.email == email

    resp = client.get("/login0", headers={"Authorization": auth})
    assert resp.status_code == 302
    assert current_user.email == email

    from base64 import b64encode
    resp = client.get(
        "/login0",
        headers={"Authorization": b64encode(auth.encode()).decode()})
    assert resp.status_code == 302
    assert current_user.email == email
Exemple #5
0
    def __init__(self,
                 secret_key,
                 *,
                 cookie_name="AIOHTTP_SESSION",
                 domain=None,
                 max_age=None,
                 path="/",
                 secure=None,
                 httponly=True,
                 encoder=json.dumps,
                 decoder=json.loads):
        super().__init__(
            cookie_name=cookie_name,
            domain=domain,
            max_age=max_age,
            path=path,
            secure=secure,
            httponly=httponly,
            encoder=encoder,
            decoder=decoder,
        )

        if isinstance(secret_key, str):
            pass
        elif isinstance(secret_key, (bytes, bytearray)):
            secret_key = base64.urlsafe_b64encode(secret_key)
        self._s = itsdangerous.Signer(secret_key)
Exemple #6
0
    def get_or_create_cookie(self, secret=None):
        """Find the cookie for the given user
        Create a new session if no cookie is found

        :param str secret: The key to sign the cookie with
        :returns: The signed cookie
        """
        secret = secret or settings.SECRET_KEY
        sessions = Session.find(
            Q('data.auth_user_id', 'eq', self._id)
        ).sort(
            '-date_modified'
        ).limit(1)

        if sessions.count() > 0:
            user_session = sessions[0]
        else:
            user_session = Session(data={
                'auth_user_id': self._id,
                'auth_user_username': self.username,
                'auth_user_fullname': self.fullname,
            })
            user_session.save()

        signer = itsdangerous.Signer(secret)
        return signer.sign(user_session._id)
Exemple #7
0
 def __init__(self, loop):
     self.loop = loop
     self.model_hash_registry = dict()
     self.model_dir = '/opt/model_store'
     self.temp_file_lock = asyncio.Lock()
     self.signer = itsdangerous.Signer(os.environ['SIGNING_TOKEN'])
     self.serializer = itsdangerous.Serializer(os.environ['SIGNING_TOKEN'])
Exemple #8
0
 def __init__(self,
              app: ASGIApp,
              secret_key: str,
              session_cookie: str = "session") -> None:
     self.app = app
     self.signer = itsdangerous.Signer(secret_key)
     self.session_cookie = session_cookie
Exemple #9
0
def before_request():
    # TODO: Fix circular import
    from framework.auth.core import get_user
    from framework.auth import cas
    from website.util import time as util_time

    # Central Authentication Server Ticket Validation and Authentication
    ticket = request.args.get('ticket')
    if ticket:
        service_url = furl.furl(request.url)
        service_url.args.pop('ticket')
        # Attempt to authenticate wih CAS, and return a proper redirect response
        return cas.make_response_from_ticket(ticket=ticket,
                                             service_url=service_url.url)

    if request.authorization:
        user = get_user(email=request.authorization.username,
                        password=request.authorization.password)
        # Create an empty session
        # TODO: Shoudn't need to create a session for Basic Auth
        user_session = Session()
        set_session(user_session)

        if user:
            user_addon = user.get_addon('twofactor')
            if user_addon and user_addon.is_confirmed:
                otp = request.headers.get('X-OSF-OTP')
                if otp is None or not user_addon.verify_code(otp):
                    # Must specify two-factor authentication OTP code or invalid two-factor authentication OTP code.
                    user_session.data['auth_error_code'] = http.UNAUTHORIZED
                    return
            user_session.data['auth_user_username'] = user.username
            user_session.data['auth_user_id'] = user._primary_key
            user_session.data['auth_user_fullname'] = user.fullname
        else:
            # Invalid key: Not found in database
            user_session.data['auth_error_code'] = http.UNAUTHORIZED
        return

    cookie = request.cookies.get(settings.COOKIE_NAME)
    if cookie:
        try:
            session_id = itsdangerous.Signer(
                settings.SECRET_KEY).unsign(cookie)
            user_session = Session.load(session_id) or Session(_id=session_id)
        except itsdangerous.BadData:
            return
        if not util_time.throttle_period_expired(user_session.date_created,
                                                 settings.OSF_SESSION_TIMEOUT):
            if user_session.data.get(
                    'auth_user_id') and 'api' not in request.url:
                database['user'].update(
                    {'_id': user_session.data.get('auth_user_id')},
                    {'$set': {
                        'date_last_login': datetime.utcnow()
                    }},
                    w=0)
            set_session(user_session)
        else:
            remove_session(user_session)
def verify_state(state):
    """Verify the state GitHub returned is valid

    See `generate_state` for how this is verified
    """
    signer = itsdangerous.Signer(os.environ['STATE_KEY'])
    return signer.validate(state)
Exemple #11
0
def create_session(response, data=None):
    Session = apps.get_model('osf.Session')
    current_session = get_session()
    if current_session:
        current_session.data.update(data or {})
        current_session.save()
        cookie_value = itsdangerous.Signer(settings.SECRET_KEY).sign(current_session._id)
    else:
        session_id = str(bson.objectid.ObjectId())
        new_session = Session(_id=session_id, data=data or {})
        new_session.save()
        cookie_value = itsdangerous.Signer(settings.SECRET_KEY).sign(session_id)
        set_session(new_session)
    if response is not None:
        response.set_cookie(settings.COOKIE_NAME, value=cookie_value, domain=settings.OSF_COOKIE_DOMAIN,
                            secure=settings.SESSION_COOKIE_SECURE, httponly=settings.SESSION_COOKIE_HTTPONLY)
        return response
Exemple #12
0
def before_request():

    if request.authorization:

        # Create a session from the API key; if key is
        # not valid, save the HTTP error code in the
        # "auth_error_code" field of session.data

        # Create empty session
        session = Session()

        # Hack: Avoid circular import
        from website.project.model import ApiKey

        api_label = request.authorization.username
        api_key_id = request.authorization.password
        api_key = ApiKey.load(api_key_id)

        if api_key:
            user = api_key.user__keyed and api_key.user__keyed[0]
            node = api_key.node__keyed and api_key.node__keyed[0]

            session.data['auth_api_label'] = api_label
            session.data['auth_api_key'] = api_key._primary_key
            if user:
                session.data['auth_user_username'] = user.username
                session.data['auth_user_id'] = user._primary_key
                session.data['auth_user_fullname'] = user.fullname

            elif node:
                session.data['auth_node_id'] = node._primary_key

            else:
                # Invalid key: Not attached to user or node
                session.data['auth_error_code'] = http.FORBIDDEN

        else:

            # Invalid key: Not found in database
            session.data['auth_error_code'] = http.FORBIDDEN

        set_session(session)
        return

    cookie = request.cookies.get(settings.COOKIE_NAME)
    if cookie:
        try:
            session_id = itsdangerous.Signer(
                settings.SECRET_KEY).unsign(cookie)
            session = Session.load(session_id) or Session(_id=session_id)
            set_session(session)
            return
        except:
            pass
    ## TODO: Create session in before_request, cookie in after_request
    ## Retry request, preserving status code
    #response = redirect(request.path, code=307)
    return create_session(None)
 def setUp(self):
     super(TestAddonLogs, self).setUp()
     self.user = AuthUserFactory()
     self.auth_obj = Auth(user=self.user)
     self.node = ProjectFactory(creator=self.user)
     self.session = Session(data={'auth_user_id': self.user._id})
     self.session.save()
     self.cookie = itsdangerous.Signer(settings.SECRET_KEY).sign(self.session._id)
     self.configure_addon()
Exemple #14
0
    def test_cookie_has_admin(self):
        session = Session(data={'auth_user_id': self.user._id})
        session.save()
        cookie = itsdangerous.Signer(settings.SECRET_KEY).sign(session._id)
        self.app.set_cookie(settings.COOKIE_NAME, str(cookie))

        res = self.app.get(self.url)
        assert_equal(res.status_code, 200)
        assert_equal(res.json['meta']['admin'], True)
Exemple #15
0
 def setUp(self):
     super(TestSloanMetrics, self).setUp()
     self.user = AuthUserFactory()
     self.auth_obj = Auth(user=self.user)
     self.preprint = PreprintFactory(creator=self.user, is_public=True)
     self.session = Session(data={'auth_user_id': self.user._id})
     self.session.save()
     self.cookie = itsdangerous.Signer(settings.SECRET_KEY).sign(self.session._id).decode()
     self.JWE_KEY = jwe.kdf(settings.WATERBUTLER_JWE_SECRET.encode('utf-8'), settings.WATERBUTLER_JWE_SALT.encode('utf-8'))
Exemple #16
0
        def api_login():
            data = {"status": "error"}
            if flask.request.is_json:
                json = flask.request.get_json()
                username = json.get('username', None)
                password = json.get('password', None)
                validate_code = json.get('validate_code', None)
                if not validate_code:
                    data["reason"] = "no_validate_code"
                    return flask.jsonify(data)
                if not check_validate_code(validate_code):
                    data["reason"] = "error_validate_code"
                    return flask.jsonify(data)
                if username == '':
                    username = "******"
                if username:
                    user_info = self.check_user_password(username, password)
                    if user_info:
                        uid = str(uuid.uuid1())
                        signed_uid = itsdangerous.Signer(user_info.password, salt='LoginChecker:uid').sign(
                            uid.encode(errors='ignore')).decode(
                            errors='ignore')
                        self.signed_uid = signed_uid
                        self.username = username
                        self.uid = uid
                        self.is_admin = user_info.is_admin
                        self.user_id = user_info.id
                        self.role = user_info.role
                        if use_mongoengine:
                            user_login_data = UserLoginData(uid=uid, user=user_info, username=username,
                                                            timestamp=int(time.time() * 1e3),
                                                            datetime=datetime.now(),
                                                            utc_datetime=datetime.utcnow())
                            user_login_data.save()
                            logger.info("<username=%s,uid=%s> save login with mongodb" % (username, uid))
                        elif use_peewee:
                            with db.execution_context():
                                UserLoginData.create(uid=uid, user=user_info, username=username,
                                                     timestamp=int(time.time() * 1e3),
                                                     datetime=datetime.now(),
                                                     utc_datetime=datetime.utcnow())
                                logger.info("<username=%s,uid=%s> save login with peewee" % (username, uid))
                        data["status"] = "ok"
                        data["username"] = self.username
                        data["is_admin"] = self.is_admin
                        data["role"] = self.role
                        data["uid"] = self.signed_uid
                        data["_csrf_token"] = get_csrf_token()
                        resp = flask.make_response(flask.jsonify(data))
                        self.save_login_info_to_cookie(resp)
                        return resp
                data["reason"] = "error_user"
            else:
                data["reason"] = "no_json"

            return flask.jsonify(data)
 def setUp(self):
     super(TestAddonAuth, self).setUp()
     self.user = AuthUserFactory()
     self.auth_obj = Auth(user=self.user)
     self.node = ProjectFactory(creator=self.user)
     self.session = Session(data={'auth_user_id': self.user._id})
     self.session.save()
     self.cookie = itsdangerous.Signer(settings.SECRET_KEY).sign(self.session._id)
     self.configure_addon()
     self.JWE_KEY = jwe.kdf(settings.WATERBUTLER_JWE_SECRET.encode('utf-8'), settings.WATERBUTLER_JWE_SALT.encode('utf-8'))
Exemple #18
0
def get_user_from_cookie(cookie):
    if not cookie:
        return None
    try:
        token = itsdangerous.Signer(settings.SECRET_KEY).unsign(cookie)
    except itsdangerous.BadSignature:
        raise HTTPError(httplib.UNAUTHORIZED)
    session = Session.load(token)
    if session is None:
        raise HTTPError(httplib.UNAUTHORIZED)
    return User.load(session.data['auth_user_id'])
Exemple #19
0
def generate_signed_id(secret):
    ''' Generate a unique ID with a signature.
    
        We want this to include date for sorting, be a valid ISO-8601 datetime,
        and to use a big random number for fake nanosecond accuracy to increase
        likelihood of uniqueness.
    '''
    now, nsec = datetime.datetime.utcnow(), random.randint(0, 999999999)
    identifier = '{}.{:09d}Z'.format(now.strftime('%Y%m%dT%H%M%S'), nsec)
    signer = itsdangerous.Signer(secret)
    return identifier, signer.sign(identifier.encode('utf8')).decode('utf8')
Exemple #20
0
 def setUp(self):
     super(TestAddonAuth, self).setUp()
     self.flask_app = SetEnvironMiddleware(self.app.app, REMOTE_ADDR='127.0.0.1')
     self.test_app = webtest.TestApp(self.flask_app)
     self.user = AuthUserFactory()
     self.auth_obj = Auth(user=self.user)
     self.node = ProjectFactory(creator=self.user)
     self.session = Session(data={'auth_user_id': self.user._id})
     self.session.save()
     self.cookie = itsdangerous.Signer(settings.SECRET_KEY).sign(self.session._id)
     self.configure_addon()
Exemple #21
0
def socketio(remaining):
    real_request = request._get_current_object()
    # add redis connection
    real_request._conn = get_connection()
    real_request._data_root = current_app.config.get('DATA_ROOT')
    real_request._signer = itsdangerous.Signer(current_app.secret_key)
    socketio_manage(request.environ, {
        '/status': StatusNamespace,
        '/build': BuildNamespace,
    },
                    request=real_request)
    return Response()
Exemple #22
0
    def setUp(self):
        super(TestUserLastLoginDate, self).setUp()

        self.user = AuthUserFactory()

        self.session = SessionFactory(
            data={
                'auth_user_id': self.user._id,
                'auth_user_username': self.user.username
            }
        )
        self.cookie = itsdangerous.Signer(settings.SECRET_KEY).sign(self.session._id).decode()
Exemple #23
0
def before_request():
    from framework.auth import cas

    # Central Authentication Server Ticket Validation and Authentication
    ticket = request.args.get('ticket')
    if ticket:
        service_url = furl.furl(request.url)
        service_url.args.pop('ticket')
        # Attempt autn wih CAS, and return a proper redirect response
        resp = cas.make_response_from_ticket(ticket=ticket, service_url=service_url.url)
        if request.cookies.get(settings.COOKIE_NAME):
            # TODO: Delete legacy cookie, this special case can be removed anytime after 1/1/2016.
            # A cookie is received which could potentially be a legacy (pre multi-domain) cookie.
            # Issuing a targeted delete of the legacy cookie ensures the user does not end up in a
            # login loop whereby both cookies are sent to the server and one of them at random
            # read for authentication.
            resp.delete_cookie(settings.COOKIE_NAME, domain=None)
        return resp

    if request.authorization:
        # TODO: Fix circular import
        from framework.auth.core import get_user
        user = get_user(
            email=request.authorization.username,
            password=request.authorization.password
        )
        # Create empty session
        # TODO: Shoudn't need to create a session for Basic Auth
        session = Session()

        if user:
            session.data['auth_user_username'] = user.username
            session.data['auth_user_id'] = user._primary_key
            session.data['auth_user_fullname'] = user.fullname
            user.date_last_login = datetime.utcnow()
            user.save()
        else:
            # Invalid key: Not found in database
            session.data['auth_error_code'] = http.FORBIDDEN

        set_session(session)
        return

    cookie = request.cookies.get(settings.COOKIE_NAME)
    if cookie:
        try:
            session_id = itsdangerous.Signer(settings.SECRET_KEY).unsign(cookie)
            session = Session.load(session_id) or Session(_id=session_id)
        except itsdangerous.BadData:
            return
        if session.data.get('auth_user_id'):
            database['user'].update({'_id': session.data.get('auth_user_id')}, {'$set': {'date_last_login': datetime.utcnow()}}, w=0)
        set_session(session)
Exemple #24
0
 def __init__(self, loop):
     self.loop = loop
     self.uid = str(uuid.uuid4())
     self.model_hash_registry = dict()
     self.model_dir = '/opt/model_store'
     self.temp_file_lock = asyncio.Lock()
     self.signer = itsdangerous.Signer(os.environ['SIGNING_TOKEN'])
     self.serializer = itsdangerous.Serializer(os.environ['SIGNING_TOKEN'])
     self.model_hash = os.environ['GENREML_MODEL_HASH']
     self.model_path = self.get_model_path(self.model_hash)
     if not self.check_model_hash(self.model_hash) is True:
         eprint("model not found during init")
Exemple #25
0
def lambda_handler(event, context):
    '''
    '''
    s3 = boto3.client('s3', endpoint_url=constants.S3_ENDPOINT_URL)
    query = util.event_query_args(event)
    website_base = constants.WEBSITE_BASE

    try:
        id = itsdangerous.Signer(constants.SECRET).unsign(
            query['id']).decode('utf8')
    except itsdangerous.BadSignature:
        return {
            'statusCode': '400',
            'headers': {
                'Access-Control-Allow-Origin': '*'
            },
            'body': 'Bad ID'
        }

    if query.get('incumbency') == 'yes':
        rules = {
            rule.endpoint: str(rule)
            for rule in website.app.url_map.iter_rules()
        }
        redirect_url = urllib.parse.urljoin(website_base,
                                            rules['get_incumbency'])
        return {
            'statusCode': '302',
            'headers': {
                'Location': redirect_url
            },
            'body': ''
        }

    upload = create_upload(s3, query['bucket'], query['key'], id)
    redirect_url = get_redirect_url(website_base, id)

    event = dict(bucket=query['bucket'])
    event.update(upload.to_dict())

    lam = boto3.client('lambda', endpoint_url=constants.LAMBDA_ENDPOINT_URL)
    lam.invoke(FunctionName=after_upload.FUNCTION_NAME,
               InvocationType='Event',
               Payload=json.dumps(event).encode('utf8'))

    return {
        'statusCode': '302',
        'headers': {
            'Location': redirect_url
        },
        'body': ''
    }
    def test_cookied_requests_can_create_and_email(self, mock_mail, app, user,
                                                   email_unconfirmed, data,
                                                   url_base):
        session = Session(data={'auth_user_id': user._id})
        session.save()
        cookie = itsdangerous.Signer(settings.SECRET_KEY).sign(session._id)
        app.set_cookie(settings.COOKIE_NAME, str(cookie))

        assert OSFUser.objects.filter(username=email_unconfirmed).count() == 0
        res = app.post_json_api('{}?send_email=true'.format(url_base), data)
        assert res.status_code == 201
        assert OSFUser.objects.filter(username=email_unconfirmed).count() == 1
        assert mock_mail.call_count == 1
Exemple #27
0
 def is_login(self):
     if self.username is None:
         username = flask.request.cookies.get('MEMBER_LOGIN', None)
         signed_uid = flask.request.cookies.get('UID', None)
         if username and signed_uid and (use_mongoengine or use_peewee):
             user_info = self.get_user_info(username)
             if user_info:
                 try:
                     uid = itsdangerous.Signer(user_info.password, salt='LoginChecker:uid').unsign(
                         signed_uid).decode(
                         errors='ignore')
                 except itsdangerous.BadData:
                     return False
                 if use_mongoengine:
                     user_login_data = UserLoginData.objects(uid=uid, user=user_info.id, username=username).first()
                     if user_login_data:
                         self.is_admin = user_info.is_admin
                         self.username = username
                         self.uid = uid
                         self.signed_uid = signed_uid
                         self.user_id = user_info.id
                         self.role = user_info.role
                         user_login_data.timestamp = int(time.time() * 1e3)
                         user_login_data.datetime = datetime.now()
                         user_login_data.utc_datetime = datetime.utcnow()
                         user_login_data.save()
                         logger.info("<username=%s,uid=%s> pass login with mongodb" % (username, uid))
                         return True
                     return False
                 elif use_peewee:
                     with db.execution_context():
                         user_login_data = UserLoginData.get(UserLoginData.uid == uid,
                                                             UserLoginData.user == user_info.id,
                                                             UserLoginData.username == username)
                         if user_login_data:
                             self.is_admin = user_info.is_admin
                             self.username = username
                             self.uid = uid
                             self.signed_uid = signed_uid
                             self.user_id = user_info.id
                             self.role = user_info.role
                             user_login_data.timestamp = int(time.time() * 1e3)
                             user_login_data.datetime = datetime.now()
                             user_login_data.utc_datetime = datetime.utcnow()
                             user_login_data.save()
                             logger.info("<username=%s,uid=%s> pass login with peewee" % (username, uid))
                             return True
                         return False
             return False
         return False
     return True
Exemple #28
0
def get_session_from_cookie(cookie_val):
    """
    Given a cookie value, return the `Session` object or `None`.

    :param cookie_val: the cookie
    :return: the `Session` object or None
    """

    session_id = itsdangerous.Signer(settings.SECRET_KEY).unsign(cookie_val)
    try:
        session = Session.objects.get(_id=session_id)
        return session
    except Session.DoesNotExist:
        return None
Exemple #29
0
    def test_cookied_requests_can_create_and_email(self, mock_mail):
        session = Session(data={'auth_user_id': self.user._id})
        session.save()
        cookie = itsdangerous.Signer(settings.SECRET_KEY).sign(session._id)
        self.app.set_cookie(settings.COOKIE_NAME, str(cookie))

        assert_equal(
            User.find(Q('username', 'eq', self.unconfirmed_email)).count(), 0)
        res = self.app.post_json_api(
            '{}?send_email=true'.format(self.base_url), self.data)
        assert_equal(res.status_code, 201)
        assert_equal(
            User.find(Q('username', 'eq', self.unconfirmed_email)).count(), 1)
        assert_equal(mock_mail.call_count, 1)
Exemple #30
0
 def _get_signer(self):
     if not self._secret_key:
         apm.capture_message('Secret key not set.')
         logger.error({'message': 'Secret key not set.'})
         return None
     if not self._salt:
         apm.capture_message('Salt not set.')
         logger.error({'message': 'Salt not set.'})
         return None
     return itsdangerous.Signer(
         secret_key=self._secret_key,
         salt=self._salt,
         key_derivation='hmac'
     )