jaredhendrickson13/pfsense-saml2-auth

Questions about custom section

Glowsome opened this issue · 17 comments

If it is possible i would appreciate some additional explanation on how to use the custom settings.

Even after reading the referenced oneLogin doc i am still struggling as to what exactly is expected in like an example.

This would be highly appreciated from my end.

  • Glowsome

Hey!

The custom settings allow you to add additional settings fields and values that are supported by the OneLogin php-saml library but may be missing the pfSense SAML2 package's UI. In most use cases the custom settings are not necessary. The settings in the pfSense SAML2 package's UI relate to specific fields in the OneLogin php-saml library's settings array. Since the UI doesn't contain a field for every supported field in the php-saml library, the custom settings allow you to specify these additional fields and values in a JSON format.

As a primitive example. If you look at the OneLogin library's advanced settings example, you'll see it contains fields for compression on lines 9-12 that are not present in the pfSense SAML2's UI. You could still configure these settings by adding the following JSON string in the custom settings within the UI:

{"compress": {"requests": true, "responses": true}}

Again these types of settings typically are not required by most IdPs and unless you know specifically what fields are required for your IdP they may cause more harm than good. Anyway, hope this helps. Feel free to let me know if you have any other questions.

Thanks!

Hi , and first of all thankyou for your reply.
As my request was kind-of general i would like to elaborate to the part i am struggling with :

the part after having setup the required parameters the metadata reads :

<md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> <md:NameIDFormat>
Now for me the thing i am looking for are the settings 'AuthnRequestsSigned' and 'WantAssertionsSigned' to reflect the value 'true'

i must admit that i'm kind-of noob-ish in this and from all attempts i did undertake did not take hold.

so any directions in this from your end are greatly appreciated.

Secondary (without enabling the saml auth itself) and reviewing it i dont see any certificate from the SP in the metadata.
So either i am missing something or i do need to specify the certificate for the SAML-connection over the custom-settings itself.

For your information the IDP i will be attempting this on is a Microfocus Access Manager ( formerly NetIQ, and before that this was a Novell brand)

Just been trying out more , and if i specify the parameters in a/the corect json format :
{"security": { "authnRequestsSigned": true, "wantAssertionsSigned": true, } }
The parameters get accepted, but as there is no cert yet it will moan with an error that certificate is required somehow will need to drop it in there too.

i also found that i can add the certificate via the json below:
{"sp": { "x509cert": "MY_X509_CERTIFICATE_STRING-Without BEGIN/END CERTIFICATE tags", "privateKey": "MY PRIVATE_KEY_STRING-Without BEGIN/END KEY tags", } }
However as that section is part of the default/regular settings, and not the advanced settings i somehow need to combine them.
up untill now i have not yet figured that out.

You can just combine your JSON strings to do this:

{
    "security": { 
        "authnRequestsSigned": true, 
        "wantAssertionsSigned": true
    }, 
    "sp": { 
        "x509cert": "MY_X509_CERTIFICATE_STRING-Without BEGIN/END CERTIFICATE tags", 
        "privateKey": "MY PRIVATE_KEY_STRING-Without BEGIN/END KEY tags" 
    } 
}

The settings will be merged by the backend so you shouldn't need to worry about that.

You can just combine your JSON strings to do this:

{
    "security": { 
        "authnRequestsSigned": true, 
        "wantAssertionsSigned": true
    }, 
    "sp": { 
        "x509cert": "MY_X509_CERTIFICATE_STRING-Without BEGIN/END CERTIFICATE tags", 
        "privateKey": "MY PRIVATE_KEY_STRING-Without BEGIN/END KEY tags" 
    } 
}

The settings will be merged by the backend so you shouldn't need to worry about that.

That is what i expected/assumes when trying however the result with your example is that neither the cert nor the security settings are applied to the metadata.

[edit] got it now - on to adding more ( my idp expects certain tags to be present).

Thankyou for your help in clarifying stuff for me 👍

Glad you got things figured out. Let me know if anything else comes up. Happy to help however I can.

For your info ...
I used a JSON-checker that (from their end) conveniently stripped off a comma which i placed wrongly and instead of marking it as an 'error' it just informed me it did that, and then still validated the json as RFC-compliant.
And that misplaced comma basically made the whole json being ignored in the config.

Last thing i am now struggling with is the mention in the generated Metadata is the validUntil - tag ... as my IDP is not capable of dynamically reloading Metadata on the fly.
So i added the tag in the JSON, but its not taking hold.

Question is, is it in the version i am running supported? ( as i am still running 2.4.5-RELEASE-p1, package i installed is the 2.4 version ) and i see some discussions in the onelogin page where this parameter is discussed.
Just checking if it is in there before i bang my head further against the wall trying to get this configured.

At the moment my json looks as following :

{
  "sp":
    {
    "x509cert": "MY_X509_CERTIFICATE_STRING-Without BEGIN/END CERTIFICATE tags",
    "privateKey": "MY PRIVATE_KEY_STRING-Without BEGIN/END KEY tags",
	"singleLogoutService":
	  {
	  "url": "https://pfSense.mydomain.tld/saml2_auth/slo",
	  "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
	  },
	"validUntil": "2025-06-14T02:28:42Z"
  },
  
  "idp":
    {
	"singleLogoutService":
	  {
	  "url": "https://login.mydomain.tld/nidp/saml2/slo",
	  "responseUrl": "https://login.mydomain.tld.nl/nidp/saml2/slo_return",
	  "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
	  }
	},
  "security":
    {
	  "authnRequestsSigned": true,
      "wantAssertionsSigned": true
	}
}

Doesnt seem like the code-tag likes my formatting .. sorry for that.

I'll see what I can do as far as field validation on the custom settings in the UI, a simple check to ensure the JSON string can be decoded before accepting the input. Might save others some headache in the future.

The package is supported on pfSense 2.4.5 and should work exactly the same across all supported releases. The only differences pertain to pfSense itself not the php-saml library.

As far as the validUntil tag, I'm not sure that is an allowed setting in the php-saml library. I don't see it referenced as such in the OneLogin_Saml2_Settings class at least but I could be wrong there. It's possible that it is expecting a unix timestamp instead of a date time string or something like that.

Best of luck to you, let me know if there's anything else I can help with in the meantime.

Thanks!

Best of luck to you, let me know if there's anything else I can help with in the meantime.

Thanks!

I am more then pleased with the feedback you have provided on my inquiries so from me on that you get a big 👍 alltogether.
The type of feedback you have provided is very noteworthy and has helped me for a very large portion of looking at this type of authentication.

And as a reference, the JSON validator i used was : https://jsonformatter.curiousconcept.com/

  • Glowsome

I seem to have my custom section in order however when i activate the config and click the "Login with SSO" i immediately get an error from xmlsec:

Fatal error: Uncaught Exception: Failure Signing Data: error:0906D064:PEM routines:PEM_read_bio:bad base64 decode - SHA256 in /etc/inc/saml2_auth/lib/xmlseclibs-3.1.0/src/XMLSecurityKey.php:551 Stack trace: #0 /etc/inc/saml2_auth/lib/xmlseclibs-3.1.0/src/XMLSecurityKey.php(631): RobRichards\XMLSecLibs\XMLSecurityKey->signOpenSSL('SAMLRequest=lVN...') #1 /etc/inc/saml2_auth/lib/php-saml-3.5.1/src/Saml2/Auth.php(755): RobRichards\XMLSecLibs\XMLSecurityKey->signData('SAMLRequest=lVN...') #2 /etc/inc/saml2_auth/lib/php-saml-3.5.1/src/Saml2/Auth.php(692): OneLogin\Saml2\Auth->buildMessageSignature('lVNdb+IwEHznV6C...', 'https://pfSense...', 'http://www.w3.o...', 'SAMLRequest') #3 /etc/inc/saml2_auth/lib/php-saml-3.5.1/src/Saml2/Auth.php(558): OneLogin\Saml2\Auth->buildRequestSignature('lVNdb+IwEHznV6C...', 'https://pfSense...', 'http://www.w3.o...') #4 /etc/inc/saml2_auth/SAML2Auth.inc(42): OneLogin\Saml2\Auth->login('https://pfSense...') #5 /usr/local/www/saml2_auth/sso/index.php(21): SAML2Auth->sso('https://pfSense...') #6 { in /etc/inc/saml2_auth/lib/xmlseclibs-3.1.0/src/XMLSecurityKey.php on line 551 PHP ERROR: Type: 1, File: /etc/inc/saml2_auth/lib/xmlseclibs-3.1.0/src/XMLSecurityKey.php, Line: 551, Message: Uncaught Exception: Failure Signing Data: error:0906D064:PEM routines:PEM_read_bio:bad base64 decode - SHA256 in /etc/inc/saml2_auth/lib/xmlseclibs-3.1.0/src/XMLSecurityKey.php:551 Stack trace: #0 /etc/inc/saml2_auth/lib/xmlseclibs-3.1.0/src/XMLSecurityKey.php(631): RobRichards\XMLSecLibs\XMLSecurityKey->signOpenSSL('SAMLRequest=lVN...') #1 /etc/inc/saml2_auth/lib/php-saml-3.5.1/src/Saml2/Auth.php(755): RobRichards\XMLSecLibs\XMLSecurityKey->signData('SAMLRequest=lVN...') #2 /etc/inc/saml2_auth/lib/php-saml-3.5.1/src/Saml2/Auth.php(692): OneLogin\Saml2\Auth->buildMessageSignature('lVNdb+IwEHznV6C...', 'https://pfSense...', 'http://www.w3.o...', 'SAMLRequest') #3 /etc/inc/saml2_auth/lib/php-saml-3.5.1/src/Saml2/Auth.php(558): OneLogin\Saml2\Auth->buildRequestSignature('lVNdb+IwEHznV6C...', 'https://pfSense...', 'http://www.w3.o...') #4 /etc/inc/saml2_auth/SAML2Auth.inc(42): OneLogin\Saml2\Auth->login('https://pfSense...') #5 /usr/local/www/saml2_auth/sso/index.php(21): SAML2Auth->sso('https://pfSense...') #6 {

i have tested the cert string i am inputting with a cert-tester, and that seems to be ok.

if i drop the custom config i get rejected (RequestDenied) by the IDP, looking at logs thre says : "Digital signature is required"

So i seem to be a bit 'stuck'

Gotten a bit further :

As previously mentioned i put in the certificate and key as a string without beginning or end-tags.
This does show up correctly in the Metadata, but the xmsecllib expects them to be there.
So after some googling i changed the custom setting of both the key to the following :

  1. prepend the certificate/key string with either the appropriate -----BEGIN CERTIFICATE-----\n or -----BEGIN PRIVATE KEY-----\n
  2. remove all spaces between the lines of the certificate.

This still kept the certificate intact on the Metadata, however if i click the SSO login xmlseclib it now moans about string too long.
Further googling/investigating i replaced the spaces on the certificate with \n and included the end-certificate/Key tags aswell, then resubmitted it to the custom settings JSON.

=>> success , no more moans of xmlSeclibs ...

Now on to the next hurdle , as now i have an error stating :
The status code of the Response was not Success, was Responder -> urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy invalid_response The status code of the Response was not Success, was Responder -> urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy
.. creeping forward step by step :)

@jaredhendrickson13 , its fun to dive in to such stuff , and to help others reporting back so other in the future can make use of this :)

Another Update from me...

The above error was relayed as i had set the respoce type on the IDP to 'Artefact', whereas OneLogin expects HTTP-POST.
Switching this on the IDP-side got me further, but then it started to moan about missing 'RequestedAuthNcontext'.

To counter this i have added the parameter requestedAuthnContext to my json ( with the urn of an authentication-context present on my IDP.

After adding this its no longer moaning about this, but now its moaning about casing of the responce.

The response was received at https://pfsense.mydomain.tld/saml2_auth/sso/acs/ instead of https://pfSense.mydomain.tld/saml2_auth/sso/acs/

invalid_response

The response was received at https://pfsense.mydomain.tld/saml2_auth/sso/acs/ instead of https://pfSense.mydomain.tld/saml2_auth/sso/acs/

So it seems now that its stumbling over a casing-issue.

Solved the Casing problem, it was in the entries for the SP name in pfSense ... now on to the next error.

<samlp:Status>
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder">
            <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:RequestDenied" />
        </samlp:StatusCode>
        <samlp:StatusMessage>Authorization is failed</samlp:StatusMessage>
</samlp:Status>

Seems even tho i have set the 'WantsAssetionsSigned" on the SP (and my IDP also demands it/reflected in its Metadata) the AuthRrequest is not signed, and i do see a comparison for the context, but not the 'set' contract .. so need to dig a bit deeper on that :

<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                    ID="ONELOGIN_e383eee8495651dc24ba621a2cdcdd9d8288615f"
                    Version="2.0"
                    IssueInstant="2021-10-17T21:40:08Z"
                    Destination="https://login.mydomain.tld/nidp/saml2/sso"
                    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                    AssertionConsumerServiceURL="https://pfsense.mydomain.tld/saml2_auth/sso/acs/"
                    >
    <saml:Issuer>https://pfsense.mydomain.tld/saml2_auth/sso/metadata/</saml:Issuer>
    <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
                        AllowCreate="true"
                        />
    <samlp:RequestedAuthnContext Comparison="exact" />
</samlp:AuthnRequest>

[Edit]
I found why the contexct was not present ... it has to be defined as an array :

"requestedAuthnContext": ["urn:mydomain.tld:idp:contract:password"]

Finally i got it all together. (atleast the SSO-part)

For now the custom settings look like this :

{
  "sp":
    {
    "x509cert": "-----BEGIN CERTIFICATE-----\n<certificate as a string with spacesreplaced with \n>\n-----END CERTIFICATE-----",
    "privateKey": "-----BEGIN PRIVATE KEY-----\n<key as a string with spaces replaced with \n>\n-----END PRIVATE KEY-----",
	"singleLogoutService":
	  {
	  "url": "https://pfsense.mydomain.tld/saml2_auth/slo/sls/",
	  "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
	  }
	},
  "idp":
    {
	"singleLogoutService":
	  {
	  "url": "https://login.mydomain.tld/nidp/saml2/slo",
	  "responseUrl": "https://login.mydomain.tld/nidp/saml2/slo_return",
	  "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
	  }
	
	},
  "security":
    {
	  "authnRequestsSigned": true,
      "wantAssertionsSigned": true,
	  "requestedAuthnContext": ["urn:mydomain.tld:idp:contract:password"]
	}
}

@jaredhendrickson13 this implementation was tested/done using a Microfocus AccessManager v4.5.3 IDP, so i think you can add it to the 'tested' list.

Glad to hear you got all this working. In the future, I will likely add how-to guides with instructions for setup on specific IdPs. If you feel up to writing instructions on the process you followed I'd gladly except that as a contribution. Definitely no obligation to do so, however. I'll close this issue for now, but again feel free to reach out anytime you have questions or concerns.

Thank you!