jeremyschulman / netbox-plugin-auth-saml2

Netbox plugin for SSO using SAML2
119 stars 21 forks source link

CSRF cookie not set #74

Open HungryHowies opened 8 months ago

HungryHowies commented 8 months ago

Hello,

Two weeks ago, I just started working with Netbox, we needed to configure SSO using SAML and cam across this in the Documentation.

My environment: Ubuntu 22.0.4, Nignx,NetBox version: 3.6.5, Python version: 3.10.12 && Let's encrypt.

I have had multiply issues until now, but I think most errors/issues are resolved except for this one.

CSRF verification failed. Request aborted.

You are seeing this message because this site requires a CSRF cookie when submitting forms. This cookie is required for security reasons, to ensure that your browser is not being hijacked by third parties.

If you have configured your browser to disable cookies, please re-enable them, at least for this site, or for “same-origin” requests.

Reason given for failure:

    CSRF cookie not set.

In general, this can occur when there is a genuine Cross Site Request Forgery, or when Django’s CSRF mechanism has not been used correctly. For POST forms, you need to ensure:

Your browser is accepting cookies.
The view function passes a request to the template’s render method.
In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.
The form has a valid CSRF token. After logging in in another browser tab or hitting the back button after a login, you may need to reload the page with the form, because the token is rotated after a login.
You’re seeing the help section of this page because you have DEBUG = True in your Django settings file. Change that to False, and only the initial error message will be displayed.

Not sure what was going on, past 5 days I went down a rabbit hole trying different configuration and looking for files described in the documentation. This is what I have so far.

Nginx Configuration:

root@netbox:/opt/netbox/netbox/netbox# root@netbox:/opt/netbox/netbox/netbox# cat configuration.py | egrep -v "^\s*(#|$)"
map $http_x_forwarded_proto $thescheme {
    default $scheme;
    https https;
}
server {
    listen 80 default_server;
    server_name netbox.domain.com;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl;
    server_name netbox.domain.com;
    ssl_certificate /etc/letsencrypt/live/netbox.domain.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/netbox.domain.com/privkey.pem; # managed by Certbot
    client_max_body_size 25m;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto $thescheme;
    add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';
    location /static/ {
        alias /opt/netbox/netbox/static/;
    }
    location / {
        proxy_pass http://127.0.0.1:8001;
    }
    location /login/ {
        proxy_pass http://127.0.0.1:8001/api/plugins/sso/login/;
    }    
    location /sso/ {
        proxy_pass http://127.0.0.1:8001/api/plugins/sso/;  # Must have a trailing slash to strip the original path
    }
}

Netbox configuration file ( configuration.py)

root@netbox:/opt/netbox/netbox/netbox# cat configuration.py  | egrep -v "^\s*(#|$)"
ALLOWED_HOSTS = ["netbox.domain.com","zitadel.cloud"]
DATABASE = {
    'NAME': 'netbox',         # Database name
    'USER': 'netbox',               # PostgreSQL username
    'PASSWORD': 'J5brHrAXFLQSif0K', # PostgreSQL password
    'HOST': 'localhost',      # Database server
    'PORT': '',               # Database port (leave blank for default)
    'CONN_MAX_AGE': 300,      # Max database connection age
}
REDIS = {
    'tasks': {
        'HOST': 'localhost',
        'PORT': 6379,
        'USERNAME': '',
        'PASSWORD': '',
        'DATABASE': 0,
        'SSL': False,
    },
    'caching': {
        'HOST': 'localhost',
        'PORT': 6379,
        'USERNAME': '',
        'PASSWORD': '',
        'DATABASE': 1,
        'SSL': False,
    }
}
SECRET_KEY = '!3#qSHaL&(7mw38hdF0....................................$(Oj^mKZG@$Ax'
ADMINS = [
]
ALLOW_TOKEN_RETRIEVAL = False
AUTH_PASSWORD_VALIDATORS = [
]
BASE_PATH = ''
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = [
]
CORS_ORIGIN_REGEX_WHITELIST = [
]
CSRF_COOKIE_NAME = 'csrftoken'
CSRF_TRUSTED_ORIGINS = ['https://zitadel.cloud']
DEBUG = False
DEFAULT_LANGUAGE = 'en-us'
EMAIL = {
    'SERVER': 'localhost',
    'PORT': 25,
    'USERNAME': '',
    'PASSWORD': '',
    'USE_SSL': False,
    'USE_TLS': False,
    'TIMEOUT': 10,  # seconds
    'FROM_EMAIL': '',
}
ENABLE_LOCALIZATION = False
EXEMPT_VIEW_PERMISSIONS = [
]
INTERNAL_IPS = ('127.0.0.1', '::1')
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'normal': {
            'format': '%(asctime)s %(name)s %(levelname)s: %(message)s'
        },
    },
    'handlers': {
        'file': {
            'level': 'DEBUG',
            'class': 'logging.handlers.WatchedFileHandler',
            'filename': '/var/log/netbox/netbox.log',
            'formatter': 'normal',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['file'],
            'level': 'INFO',
        },
        'netbox': {
            'handlers': ['file'],
            'level': 'INFO',
        },
    },
}
LOGIN_PERSISTENCE = False
LOGIN_REQUIRED = False
LOGIN_TIMEOUT = None
LOGOUT_REDIRECT_URL = 'home'
METRICS_ENABLED = False
PLUGINS = ['django3_saml2_nbplugin']
PLUGINS_CONFIG = {
    'django3_saml2_nbplugin': {
        'AUTHENTICATION_BACKEND': 'utilities.auth_backends.RemoteUserBackend',
        'ASSERTION_URL': 'https://netbox.domain.com',
        'ENTITY_ID':'https://netbox.domain.com',
        'METADATA_LOCAL_FILE_PATH': '/opt/netbox/DCIM.xml',
        'CUSTOM_ATTR_BACKEND': {
            "USERNAME_ATTR": "emailaddress",
            "MAIL_ATTR": "emailAddress",
            "FIRST_NAME_ATTR": "givenName",
            "LAST_NAME_ATTR": "surname",
            'ALWAYS_UPDATE_USER': True,
        }
    }
}
REMOTE_AUTH_ENABLED = True
REMOTE_AUTH_BACKEND = 'netbox.authentication.RemoteUserBackend'
BANNER_LOGIN = '<a href="/api/plugins/sso/login" class="btn btn-primary btn-block">Login with SSO</a>'
REMOTE_AUTH_AUTO_CREATE_USER = True
RELEASE_CHECK_URL = None
RQ_DEFAULT_TIMEOUT = 300
SESSION_COOKIE_NAME = 'sessionid'
SESSION_FILE_PATH = None
TIME_ZONE = 'America/Chicago'
DEBUG=True
DATE_FORMAT = 'N j, Y'
SHORT_DATE_FORMAT = 'Y-m-d'
TIME_FORMAT = 'g:i a'
SHORT_TIME_FORMAT = 'H:i:s'
DATETIME_FORMAT = 'N j, Y g:i a'
SHORT_DATETIME_FORMAT = 'Y-m-d H:i'

Here are some visuals:

netbox_login-01

auth_idp-02

auth_error-03

My IDP XML file.

<?xml version="1.0"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"                     
                     entityID="https://netbox.domain.com">
    <md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
        <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
                                Location="https://netbox.domain.com/" />
        <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified</md:NameIDFormat>         
        <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                                     Location="https://netbox.domain.com"
                                     index="1" />              
    </md:SPSSODescriptor>
</md:EntityDescriptor>

This is the closed as I got in using SSO with SAML. All other attempts have failed. Here are my failed attempts https://github.com/netbox-community/netbox/discussions/14407 Any advice, direction or help would be appreciated. I am new to this software, so the struggle is real.

Thanks, in advance

--greg