Jenkins and SAML plugin issues using SSO Auth - plugins

Jenkins v 1.597
SAML plugin v 0.3
We are using an internal PingFederated server and I have entered the xml metedata contents into the Security configuration of Jenkins.
I have tried on two servers, one set up HTTPS (SSL) and one just HTTP.
We get errors when trying to login using SSO that pertain to the https://servername/securityRealm/finishLogin redirect and the same for non-SSL server.
We are stumped on what to check here, the PingFederated administrator has it set for the postback to the securityRealm/finishLogin URL, which is what is in the code for the plugin, we just are not sure how to proceed.
The contents of the xml metadata:
<md:EntityDescriptor ID="MNkL_uYrUsdEca2oWqH6gdgG4t3" cacheDuration="PT1440M" entityID="ACIWW:Saml2:POC" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"><md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol" WantAuthnRequestsSigned="false"><md:KeyDescriptor use="signing"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data> <ds:X509Certificate>CERTIFICATECODE HERE</ds:X509Certificate></ds:X509Data> </ds:KeyInfo></md:KeyDescriptor><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://SSOSERVERNAME/idp/SSO.saml2"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://SSOSERVERNAME/idp/SSO.saml2"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://SSOSERVERNAME/idp/SSO.saml2"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://SSOSERVERNAME/idp/SSO.saml2"/></md:IDPSSODescriptor><md:ContactPerson contactType="administrative"><md:Company>COMPANYNAME</md:Company></md:ContactPerson></md:EntityDescriptor>
Any help or suggestions would be greatly appreciated.
John

Related

Elytron programmatic login with FORM authentication

we are currently migrating from legacy security subsystem to Elytron and have a Struts2 based web application deployed in JBoss EAP 7.3.6 which should support multiple "flavors" of authentication.
The standard way of logging in should be that a user manually provides credentials in a login form (j_security_check) and clicks the corresponding button. This works well with Elytron in our setup.
The second possibility is, that the GET request to protected content of the web application can contain a custom cookie that contains a JWT token. This cookie is intercepted by a io.undertow.server.HttpHandler which deals with the incoming request in its io.undertow.server.HttpHandler#handleRequest method. This handler is registered by io.undertow.servlet.api.DeploymentInfo#addSecurityWrapper with a DeploymentInfo which is provided by an implementation of io.undertow.servlet.ServletExtension. The ServletExtension is registered as a service provider in META-INF/services/io.undertow.servlet.ServletExtension.
The request handling in our implementation of io.undertow.server.HttpHandler#handleRequest extracts the JWT token from the cookie, pre-validates it and determines the contained username. This username and the token as a password are used as inputs for a call to javax.servlet.http.HttpServletRequest#login.
With the legacy security subsystem, the behavior of the server was, that this call to login triggered the authentication against the configured legacy security domain AND created a session in Undertow so that the HTTP 200 response for the previous GET request contained a Set-Cookie header with a fresh JSESSIONID cookie.
With Elytron, javax.servlet.http.HttpServletRequest#login doesn't do anything, neither an authentication against an Elytron security domain and security realm nor the creation of a session is triggered. The browser simply shows the login form which should get skipped by the described interception process.
I debugged the implementation of javax.servlet.http.HttpServletRequest#login that comes with JBoss. We start in io.undertow.servlet.spec.HttpServletRequestImpl#login which calls login = sc.login(username, password). This SecurityContext, when using Elytron, is org.wildfly.elytron.web.undertow.server.SecurityContextImpl. org.wildfly.elytron.web.undertow.server.SecurityContextImpl#login first checks if (httpAuthenticator == null). The httpAuthenticator is only set in org.wildfly.elytron.web.undertow.server.SecurityContextImpl#authenticate which gets called by a call to javax.servlet.http.HttpServletRequest#authenticate.
This explains, why a plain call to io.undertow.servlet.spec.HttpServletRequestImpl#login was doing nothing. I tried to call javax.servlet.http.HttpServletRequest#authenticate first, to instantiate that httpAuthenticator internally, and then javax.servlet.http.HttpServletRequest#login. This at least finally triggered the authentication and authorization against the configured Elytron security domain and security realm. Authentication/authorization were successful but Undertow still didn't issue a new JSESSIONID cookie and the browser again showed the login form instead of proceeding to the protected resources.
I'm currently out of ideas, how to proceed with this issue und how to achieve the same behavior as with the legacy security subsystem. Why does the Elytron implementation of io.undertow.security.api.SecurityContext behave so differently compared to the one for legacy security (io.undertow.security.impl.SecurityContextImpl)? How am I supposed to log in programatically in a FORM based web application using Elytron with javax.servlet.http.HttpServletRequest#login and/or javax.servlet.http.HttpServletRequest#authenticate?
The relevant JBoss configuration for all this looks like this:
Undertow:
<application-security-domains>
<application-security-domain name="my_app_security_domain" http-authentication-factory="MyHttpAuthFactory"/>
</application-security-domains>
Elytron:
<security-domains>
<security-domain name="MySecurityDomain" default-realm="MyCachingRealm" permission-mapper="default-permission-mapper">
<realm name="MyCachingRealm" role-decoder="FromRolesAttributeDecoder"/>
</security-domain>
</security-domains>
<security-realms>
<custom-realm name="MyCustomRealm" module="module name redacted" class-name="class name redacted"/>
<caching-realm name="MyCachingRealm" realm="MyCustomRealm" maximum-age="300000"/>
<identity-realm name="local" identity="$local"/>
</security-realms>
<mappers>
<simple-permission-mapper name="default-permission-mapper" mapping-mode="first">
<permission-mapping>
<principal name="anonymous"/>
<permission-set name="default-permissions"/>
</permission-mapping>
<permission-mapping match-all="true">
<permission-set name="login-permission"/>
<permission-set name="default-permissions"/>
</permission-mapping>
</simple-permission-mapper>
<constant-realm-mapper name="local" realm-name="local"/>
<constant-realm-mapper name="MyRealmMapper" realm-name="MyCachingRealm"/>
<simple-role-decoder name="FromRolesAttributeDecoder" attribute="Roles"/>
</mappers>
<http>
<http-authentication-factory name="MyHttpAuthFactory" security-domain="MySecurityDomain" http-server-mechanism-factory="global">
<mechanism-configuration>
<mechanism mechanism-name="FORM" realm-mapper="MyRealmMapper">
<mechanism-realm realm-name="MyRealm"/>
</mechanism>
</mechanism-configuration>
</http-authentication-factory>
<provider-http-server-mechanism-factory name="global"/>
</http>
This was a bug in JBoss EAP which has been fixed in EAP 7.3.8 and 7.4.1. See https://issues.redhat.com/browse/JBEAP-21737 and https://issues.redhat.com/browse/JBEAP-21738 for details.

Apache Knox for SAML2 authentication keeps using NameIDFormat entity instead of what is configured

I am trying to enable SSO capabilities for Apache Zeppelin, using Apache Knox, which is configured to redirect auth requests to a Siteminder IdP.
The issue I am having is related to the NameID format configuration, and the signing configuration.
No matter what I configure in the sp/idp metadata, the NameID format used is
urn:oasis:names:tc:SAML:2.0:nameid-format:entity
And the requests are always being sent with Signed requests set to true.
My SP configuration is as follows:
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://knox.test.com/gateway/knoxsso/api/v1/websso?pac4jCallback=true%26client_name=SAML2Client">
<SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol urn:oasis:names:tc:SAML:1.1:protocol http://schemas.xmlsoap.org/ws/2003/07/secext">
<NameIDFormat>
urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
</NameIDFormat>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://knox.test.com/gateway/knoxsso/api/v1/websso?pac4jCallback=true%26client_name=SAML2Client"/>
<AssertionConsumerService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" index="1" isDefault="true" Location="https://knox.test.com/gateway/knoxsso/api/v1/websso?pac4jCallback=true%26client_name=SAML2Client"/>
</SPSSODescriptor>
I activated a SAML tracer and attempted the logon user journey. The AuthNRequest being sent to the Siteminder IdP based on this configuration looks like this:
<saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"
AssertionConsumerServiceURL="https://knox.test.com/gateway/knoxsso/api/v1/websso?pac4jCallback=true%26client_name=SAML2Client"
Destination="https://test-siteminder.com/test/saml2sso"
ForceAuthn="false"
ID="_yp52mio0oj4ho2niijmnnaikgbkid9tnc5h5ear"
IsPassive="false"
IssueInstant="2020-02-17T10:19:24.279Z"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
ProviderName="pac4j-saml"
Version="2.0"
>
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
NameQualifier="https://knox.test.com/gateway/knoxsso/api/v1/websso?pac4jCallback=true%26client_name=SAML2Client"
>https://knox.test.com/gateway/knoxsso/api/v1/websso?pac4jCallback=true%26client_name=SAML2Client</saml2:Issuer>
I can see a signature value in the Parameters section of the request, which is why I'm assuming that the AuthNRequest is signed (though my understanding of this is minimal, so that could be a wrong assumption!).
Can anyone help explain why the NameIDFormat is coming through as entity, as opposed to unspecified?
Does Apache knox support SAML1 protocols?
Thanks in advance!
You mentioned NameID format to be urn:oasis:names:tc:SAML:2.0:nameid-format:entity in your post but in the code you pasted it is urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified, just a copy paste error ? Looks like protocolSupportEnumeration is also referencing SAML 1 protocol. Knox uses Pac4J under the hood which does not support SAML 1, this might be the reason.

Windows ADFS SAML markup vs Standard SAML makeup

I have a question about SAML markup. I'm currently working on a project where I need to integrate a third-party application to work with windows ADFS.
I see in the sample SAML file they have sent me the makeup always starts with <saml:....>
for example:
<saml:Assertion ...>
..
</saml:Assertion>
<saml:Subject>
</saml:Subject>
<saml:Conditions
</saml:Conditions>
<saml:AuthnStatement
</saml:AuthnStatement>
...... etc
While in Windows ADFS, the SAML file that gets generated doesn't have this saml append in it's response markup.
<Assertion ...>
..
</Assertion>
<Subject>
</Subject>
<Conditions
</Conditions>
<AuthnStatement
</AuthnStatement>
i'm getting {"non_field_errors":["invalid_response"]}after ADFS login, so I'm trying to isolate what causing this to happen. cloud this be a reason for it not to work?
Check out my channel which has more than 10 videos explaining everything related to ADFS -https://www.youtube.com/channel/UCO-AQkOHCYZias9arGmQtOA
Also check this video, to know how you can verify my answer - https://www.youtube.com/watch?v=VsjhoE-M_yk
*The sample which you have received from your team, is a SAML 1.0 token, for which the saml was supposed to be used as prefix.
Below mentioned is one example. *
*But, if you request SAML 2.0 token, this prefix will not be available. *

OKTA(IdP) - Shibboleth(SP) with reverse proxy to Tomcat

I am spinning a big wheel now. please shed some light.
Reverse proxy is working with Apache. So, when I access https://hostname/app/default.html, it opens Tomcat app url. No issue.
The tomcat app currently redirects to https://hostname/app/login.html which has a login box.
1) Do I need to disable UserDatabase on Tomcat server.xml ?
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
2) Is this Shibboleth configuration correct ?
But, when I try configure this with OKTA- Shibboleth(3.0), it's looping OKTA SSO url.
In shibboleth2.xml
<ApplicationDefaults id="default"
entityID="https://hostname/shibboleth-sp"
REMOTE_USER="userid" >
<SSO entityID="http://www.okta.com/~~~~">
OKTA's metadata is downloaded and located with shibboleth2.xml file.
cert is also generated and placed in the same folder.
3) Is this OKTA configuration correct ?
In OKTA widget configuration menu,
- Single sign on url :https://hostname/Shibboleth.sso/SAML2/POST
- recipient url : https://hostname/Shibboleth.sso/SAML2/POST
- destination url :https://hostname/Shibboleth.sso/SAML2/POST
- audience restriction :https://hostname/shibboleth-sp <-- above SP entityID
- default relay state : ??
right now, when I click on the widget on OKTA, it's looping.
https://hostname/Shibboleth.sso/SAML2/POST
contains SAML response.
then, it redirects to OKTA SSO url. It never ends.
https:// xxx.oktapreview.com/app/xx_reverse_proxy_/xxxx/sso/saml?SAMLRequest=~~~&RelayState=~~~
This contains SAML request but it looks like this.
<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
AssertionConsumerServiceURL="https://hostname/Shibboleth.sso/SAML2/POST"
Destination="https://okta sso/sso/saml"
ID="xx"
IssueInstant="2018-11-02T15:39:24Z"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Version="2.0">
<saml:Issuer
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://hostname/shibboleth-sp
</saml:Issuer>
<samlp:NameIDPolicy
AllowCreate="1"/>
Is this Issuer url correct? Why is it looping and how to fix ?
Re Q#1: You only need Tomcat users if you're going to protect an application with it, such as the Tomcat manager. Otherwise, no.
Re Q#2: You list <SSO entityID="http://www.okta.com/~~~~"> but Destination="https://okta sso/sso/saml" from the SAML. You might want to check http/https. This is a very common cause of looping. Eliminate any potential http/https inconsistency.
FWIW Issuer looks correct to me... that's what you specify in entityID="https://hostname/shibboleth-sp"

Keycloak state parameter invalid

When user clicks login, redirected to Keycloak login page & then after successful login, user comes back to application with 400 error page.
Server log shows following:
[Server:node-00] 13:40:00,709 WARN
[org.keycloak.adapters.OAuthRequestAuthenticator] (default task-30)
state parameter invalid
My application conf is:
<subsystem xmlns="urn:jboss:domain:keycloak:1.1">
<secure-deployment name="appWEB.war">
<realm>demo</realm>
<resource>app</resource>
<public-client>true</public-client>
<auth-server-url>http://localhost:8180/auth</auth-server-url>
<ssl-required>EXTERNAL</ssl-required>
</secure-deployment>
</subsystem>
Application URL is https://localhost:8443/app & redirect_url is https://localhost:8443/app/private.jsf.
When I use http, it works. But the error comes when I use same with https.
Any thoughts?
Here it can be many scenario which may failing with https
Keycloak running in https
Create self sign certification for keycloak.
Import this certificate to your local Java environment.SO handshake can be possible.
I hope you generate the certificates in keycloak you can find the the certificate inside keycloak/security/ssl.