diff --git a/README.md b/README.md
index 0502e5009..8c1a08d8f 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,12 @@
-=======
-![CI Build status](https://img.shields.io/azure-devops/build/beryjuorg/5d94b893-6dea-4f68-a8fe-10f1674fc3a9/1?style=flat-square)
+![CI Build status](https://img.shields.io/azure-devops/build/beryjuorg/passbook/1?style=flat-square)
+![Tests](https://img.shields.io/azure-devops/tests/beryjuorg/passbook/1?compact_message&style=flat-square)
+![Code Coverage](https://img.shields.io/codecov/c/gh/beryju/passbook?style=flat-square)
![Docker pulls](https://img.shields.io/docker/pulls/beryju/passbook.svg?style=flat-square)
![Docker pulls (gatekeeper)](https://img.shields.io/docker/pulls/beryju/passbook-gatekeeper.svg?style=flat-square)
![Latest version](https://img.shields.io/docker/v/beryju/passbook?sort=semver&style=flat-square)
![LGTM Grade](https://img.shields.io/lgtm/grade/python/github/BeryJu/passbook?style=flat-square)
-![Code Coverage](https://img.shields.io/codecov/c/gh/beryju/passbook?style=flat-square)
## What is passbook?
diff --git a/passbook/policies/reputation/tasks.py b/passbook/policies/reputation/tasks.py
index 916278d94..802e3d195 100644
--- a/passbook/policies/reputation/tasks.py
+++ b/passbook/policies/reputation/tasks.py
@@ -21,7 +21,6 @@ def save_ip_reputation():
for key in keys:
score = cache.get(key)
remote_ip = key.replace(CACHE_KEY_IP_PREFIX, "")
- print(remote_ip)
rep, _ = IPReputation.objects.get_or_create(ip=remote_ip)
rep.score = score
objects_to_update.append(rep)
diff --git a/passbook/policies/utils.py b/passbook/policies/utils.py
new file mode 100644
index 000000000..9643fbcc9
--- /dev/null
+++ b/passbook/policies/utils.py
@@ -0,0 +1,11 @@
+"""Policy Utils"""
+from typing import Any, Dict
+
+
+def delete_none_keys(dict_: Dict[Any, Any]) -> Dict[Any, Any]:
+ """Remove any keys from `dict_` that are None."""
+ new_dict = {}
+ for key, value in dict_.items():
+ if value is not None:
+ new_dict[key] = value
+ return new_dict
diff --git a/passbook/sources/oauth/views/core.py b/passbook/sources/oauth/views/core.py
index 23883de01..760c8df56 100644
--- a/passbook/sources/oauth/views/core.py
+++ b/passbook/sources/oauth/views/core.py
@@ -21,10 +21,12 @@ from passbook.flows.planner import (
)
from passbook.flows.views import SESSION_KEY_PLAN
from passbook.lib.utils.urls import redirect_with_qs
+from passbook.policies.utils import delete_none_keys
from passbook.sources.oauth.auth import AuthorizedServiceBackend
from passbook.sources.oauth.clients import BaseOAuthClient, get_client
from passbook.sources.oauth.models import OAuthSource, UserOAuthSourceConnection
from passbook.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
+from passbook.stages.prompt.stage import PLAN_CONTEXT_PROMPT
LOGGER = get_logger()
@@ -175,7 +177,6 @@ class OAuthCallback(OAuthClientMixin, View):
"""Prepare Authentication Plan, redirect user FlowExecutor"""
kwargs.update(
{
- # PLAN_CONTEXT_PENDING_USER: user,
# Since we authenticate the user by their token, they have no backend set
PLAN_CONTEXT_AUTHENTICATION_BACKEND: "django.contrib.auth.backends.ModelBackend",
PLAN_CONTEXT_SSO: True,
@@ -249,7 +250,13 @@ class OAuthCallback(OAuthClientMixin, View):
% {"source": self.source.name}
),
)
- context = self.get_user_enroll_context(source, access, info)
+ # Trim out all keys that have a value of None,
+ # so we use `"key" in ` checks in policies
+ context = {
+ PLAN_CONTEXT_PROMPT: delete_none_keys(
+ self.get_user_enroll_context(source, access, info)
+ )
+ }
return self.handle_login_flow(source.enrollment_flow, **context)
diff --git a/passbook/sources/saml/processors/base.py b/passbook/sources/saml/processors/base.py
index c1763bd81..34f6b7e45 100644
--- a/passbook/sources/saml/processors/base.py
+++ b/passbook/sources/saml/processors/base.py
@@ -15,6 +15,7 @@ from passbook.flows.planner import (
)
from passbook.flows.views import SESSION_KEY_PLAN
from passbook.lib.utils.urls import redirect_with_qs
+from passbook.policies.utils import delete_none_keys
from passbook.providers.saml.utils.encoding import decode_base64_and_inflate
from passbook.sources.saml.exceptions import (
MissingSAMLResponse,
@@ -153,7 +154,7 @@ class Processor:
return self._flow_response(
request,
self._source.enrollment_flow,
- **{PLAN_CONTEXT_PROMPT: name_id_filter},
+ **{PLAN_CONTEXT_PROMPT: delete_none_keys(name_id_filter)},
)
def _flow_response(