Open tacerus opened 2 years ago
hello, did you tiry with: 'AUTHENTICATION_BACKEND': REMOTE_AUTH_BACKEND, because you have 2 differents backends in your config, SAML2AttrUserBackend and SAML2CustomAttrUserBackend. regards,
Thanks a lot for the suggestion. I will try it.
Unfortunately, it does not seem to be valid syntax:
Mar 02 16:15:31 orpheus gunicorn[22363]: 'AUTHENTICATION_BACKEND': REMOTE_AUTH_BACKEND,
Mar 02 16:15:31 orpheus gunicorn[22363]: NameError: name 'REMOTE_AUTH_BACKEND' is not defined
try to move the PLUGINS_CONFIG section after REMOTEAUTH variables
Hi!
I think the issue is more related with https://github.com/jeremyschulman/django3-auth-saml2, but since I'm only using this Netbox plugin with it I hope it fits here.
I configured the plugin with Keycloak, and followed the advice and applied settings as per the screenshots from the nice fellow over in https://github.com/jeremyschulman/netbox-plugin-auth-saml2/issues/9.
The authentication itself works - Netbox login forwards to Keycloak, and after logging in there, it forwards back to Netbox - however, Netbox returns "Access Denied - You do not have permission to access this page.":
Screenshot
![image](https://user-images.githubusercontent.com/5121046/171061185-bde4c627-adce-4bba-b818-320abe9b256a.png)After enabling debug mode in Netbox, I notice the following log output:
gunicorn[30354]: django.core.exceptions.PermissionDenied: ('SAML2: missing response')
.Upon studying your code, it seems this is thrown even before the individual mapped attributes are parsed, and with the comment in https://github.com/jeremyschulman/django3-auth-saml2/blob/48a5084c24556340236350bf8008b71ec5105061/django3_auth_saml2/views.py#L68, it seems to me as if the POST response data passed to the plugin is simply empty - however, I am able to find POST response data in my browser:
Screenshot
![image](https://user-images.githubusercontent.com/5121046/171061155-e100b89d-3152-4f61-aaf6-46be1ec8f799.png)This is the SAML representation logged by Keycloak during the process:
Representation
``` { "id": "x", "clientId": "NetBox", "surrogateAuthRequired": false, "enabled": true, "alwaysDisplayInConsole": true, "clientAuthenticatorType": "client-secret", "redirectUris": [ "https://netbox.intranet.squirrelcube.com/sso/acs/" ], "webOrigins": [], "notBefore": 0, "bearerOnly": false, "consentRequired": false, "standardFlowEnabled": true, "implicitFlowEnabled": false, "directAccessGrantsEnabled": false, "serviceAccountsEnabled": false, "publicClient": false, "frontchannelLogout": true, "protocol": "saml", "attributes": { "saml_assertion_consumer_url_redirect": "https://netbox.intranet.squirrelcube.com/sso/acs/", "saml.force.post.binding": "true", "saml.multivalued.roles": "false", "frontchannel.logout.session.required": "false", "oauth2.device.authorization.grant.enabled": "false", "backchannel.logout.revoke.offline.tokens": "false", "saml.server.signature.keyinfo.ext": "false", "use.refresh.tokens": "true", "saml.signing.certificate": "x", "oidc.ciba.grant.enabled": "false", "backchannel.logout.session.required": "false", "client_credentials.use_refresh_token": "false", "saml.signature.algorithm": "RSA_SHA256", "require.pushed.authorization.requests": "false", "saml.client.signature": "false", "saml.signing.private.key": "x", "saml.allow.ecp.flow": "false", "id.token.as.detached.signature": "false", "saml.assertion.signature": "true", "client.secret.creation.time": "1653834855", "saml.encrypt": "false", "saml_assertion_consumer_url_post": "https://netbox.intranet.squirrelcube.com/sso/acs/", "saml.server.signature": "true", "exclude.session.state.from.auth.response": "false", "saml.artifact.binding.identifier": "x", "saml.artifact.binding": "false", "saml_force_name_id_format": "true", "acr.loa.map": "{}", "tls.client.certificate.bound.access.tokens": "false", "saml.authnstatement": "true", "display.on.consent.screen": "false", "saml_name_id_format": "username", "token.response.type.bearer.lower-case": "false", "saml_signature_canonicalization_method": "http://www.w3.org/2001/10/xml-exc-c14n#", "saml.onetimeuse.condition": "false" }, "authenticationFlowBindingOverrides": {}, "fullScopeAllowed": true, "nodeReRegistrationTimeout": -1, "protocolMappers": [ { "id": "x", "name": "username", "protocol": "saml", "protocolMapper": "saml-user-property-mapper", "consentRequired": false, "config": { "attribute.nameformat": "URI Reference", "user.attribute": "username", "attribute.name": "username" } }, { "id": "x", "name": "lastName", "protocol": "saml", "protocolMapper": "saml-user-property-mapper", "consentRequired": false, "config": { "attribute.nameformat": "URI Reference", "user.attribute": "lastName", "attribute.name": "last_name" } }, { "id": "x", "name": "groups", "protocol": "saml", "protocolMapper": "saml-group-membership-mapper", "consentRequired": false, "config": { "single": "true", "attribute.nameformat": "URI Reference", "full.path": "false", "attribute.name": "member" } }, { "id": "x", "name": "email", "protocol": "saml", "protocolMapper": "saml-user-property-mapper", "consentRequired": false, "config": { "attribute.nameformat": "URI Reference", "user.attribute": "email", "attribute.name": "email" } }, { "id": "x", "name": "firstName", "protocol": "saml", "protocolMapper": "saml-user-property-mapper", "consentRequired": false, "config": { "attribute.nameformat": "URI Reference", "user.attribute": "firstName", "attribute.name": "first_name" } } ], "defaultClientScopes": [ "role_list" ], "optionalClientScopes": [], "access": { "view": true, "configure": true, "manage": true } } ```And this is the configuration I added in Netbox:
Configuration
``` PLUGINS_CONFIG = { 'django3_saml2_nbplugin': { 'AUTHENTICATION_BACKEND': 'django3_saml2_nbplugin.backends.SAML2AttrUserBackend', 'DEFAULT_NEXT_URL': '/', 'ASSERTION_URL': 'https://netbox.intranet.squirrelcube.com', 'ENTITY_ID': 'NetBox', 'METADATA_LOCAL_FILE_PATH': '/opt/netbox-data/saml.xml', 'ALWAYS_UPDATE_USER': True, 'FLAGS_BY_GROUP': { 'is_staff': 'syscid_netbox_staff', 'is_superuser': 'syscid_netbox_admins' } } } REMOTE_AUTH_ENABLED = True REMOTE_AUTH_BACKEND = 'django3_saml2_nbplugin.backends.SAML2CustomAttrUserBackend' REMOTE_AUTH_HEADER = 'HTTP_REMOTE_USER' REMOTE_AUTH_AUTO_CREATE_USER = True REMOTE_AUTH_DEFAULT_GROUPS = [] REMOTE_AUTH_DEFAULT_PERMISSIONS = {} ```In an attempt to troubleshoot it, I expanded the exception to
raise PermissionDenied(errmsg, dir(req), req.GET, req.POST, req.META)
- it was not very helpful for me, but including it for completeness:Long exception
`gunicorn[30354]: django.core.exceptions.PermissionDenied: ('SAML2: missing response', ['COOKIES', 'FILES', 'GET', 'META', 'POST', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_cors_enabled', '_current_scheme_host', '_encoding', '_files', '_get_full_path', '_get_post', '_get_raw_host', '_get_scheme', '_initialize_handlers', '_load_post_and_files', '_mark_post_parse_error', '_messages', '_post', '_read_started', '_set_content_type_params', '_set_post', '_stream', '_upload_handlers', 'accepted_types', 'accepts', 'body', 'build_absolute_uri', 'close', 'content_params', 'content_type', 'encoding', 'environ', 'get_full_path', 'get_full_path_info', 'get_host', 'get_port', 'get_signed_cookie', 'headers', 'id', 'is_secure', 'method', 'parse_file_upload', 'path', 'path_info', 'prometheus_after_middleware_event', 'prometheus_before_middleware_event', 'read', 'readline', 'readlines', 'resolver_match', 'scheme', 'session', 'upload_handlers', 'user'],Would appreciate any ideas as to what else I could check!
Thanks a lot for any input!
Best, Georg