APM Sharepoint authentication
Hi Stanislas,
In a native ADFS-based SharePoint collaboration scenario you cannot use AD fallbacks. The SAML user accounts are most likely stored in many decentralized repositories, without a direct trust nor network access to them.
My goal was to get everything working without using the AD fallback at all. Well, I had to skip the support for outdated MS Office products and changed the handling of Microsoft WebDav Clients slightly. In addition I've restructured the code here and there to reduce the complexity and increase the performance...
when CLIENT_ACCEPTED {
set inject_session_cookie 0
}
when HTTP_REQUEST {
Check if APM session cookie is present and valid
if { ( [set sessionid [HTTP::cookie value "MRHSession"]] ne "" ) and
( [ACCESS::session exists -state_allow $sessionid] ) } then {
Allow the successfully pre authenticated request to pass
} else {
Check if persistent APM session cookie is present and valid
if { ( [set sessionid [HTTP::cookie value "MRHSession_SP"]] ne "" ) and
( [ACCESS::session exists -state_allow $sessionid] ) } then {
Restore APM session cookie value
HTTP::cookie insert name "MRHSession" value $sessionid
set inject_session_cookie 1
Allow the successfully pre authenticated request to pass
} else {
Enumerate explicit MS-OFBA authentication capabilities
Background: https://msdn.microsoft.com/en-us/library/office/cc313069(v=office.12).aspx
if { ( [HTTP::header "X-FORMS_BASED_AUTH_ACCEPTED"] equals "t" ) or
( [HTTP::header "X-FORMS_BASED_AUTH_ACCEPTED"] equals "f" ) } then {
Explicit MSOFBA support detected.
set authschema "ms-ofba"
} else {
Enumerate implicit MS-OFBA authentication capabilities
switch -glob -- [string tolower [HTTP::header "User-Agent"]] "*office protocol discovery*" - \
"*microsoft office*" - \
"*microsoft data access internet publishing provider*" - \
"*non-browser*" - \
"msoffice 12*" - \
"*microsoft-webdav-miniredir*" - \
{*ms frontpage 1[23456789]*} {
Implicit MSOFBA support detected.
set authschema "ms-ofba"
} "*ms frontpage*" {
Legacy client detected
set authschema "legacy"
} "*mozilla*" - \
"*opera*" {
Regular web browser detected.
set authschema "browser"
} default {
set authschema "legacy"
}
}
if { $authschema eq "ms-ofba" } then {
Send a MSOFBA compatible Access Denied response
if { [HTTP::path] ne "/sp-msofba-form" } then {
HTTP::respond 403 -version "1.1" \
content "Access Denied. Make sure that your client is correctly configured. See https://support.microsoft.com/en-us/kb/932118 for further information." \
noserver \
"Content-Type" "text/html" \
"X-FORMS_BASED_AUTH_REQUIRED" "https://[getfield [HTTP::host] ":" 1]/sp-msofba-form" \
"X-FORMS_BASED_AUTH_RETURN_URL" "https://[getfield [HTTP::host] ":" 1]/sp-msofba-completed" \
"X-FORMS_BASED_AUTH_DIALOG_SIZE" "800x600" \
"Set-Cookie" "MRHSession=deleted;path=/;secure" \
"Set-Cookie" "LastMRH_Session=deleted;path=/;secure" \
"Set-Cookie" "MRHSession=deleted; expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;secure" \
"Set-Cookie" "LastMRH_Session=deleted; expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;secure"
}
} elseif { $authschema eq "legacy" } then {
Send a regular Access Denied response
HTTP::respond 403 content "Access denied. An unsupported client access has been detected."
} else {
Let the regular web browser request pass to the APM policy
}
}
}
}
when ACCESS_SESSION_STARTED {
if { [HTTP::cookie value "SAML_Realm"] ne "" } then {
ACCESS::session data set "session.irule.realmcookie" [HTTP::cookie value "SAML_Realm"]
}
}
when ACCESS_POLICY_COMPLETED {
if { [set realm_cookie [ACCESS::session data get "session.irule.setrealmcookie"]] ne "" } then {
ACCESS::respond 302 "Location" "[ACCESS::session data get "session.server.landinguri"]" "Set-Cookie" "SAML_Realm=$realm_cookie;path=/;secure"
} else {
ACCESS::respond 302 "Location" "[ACCESS::session data get "session.server.landinguri"]"
}
}
when ACCESS_ACL_ALLOWED {
switch -glob -- [string tolower [HTTP::path]] "/sp-msofba-form" {
Successfully APM authenticated request MS-OFBA request detected. Redirect to MS-OFBA return URL
ACCESS::respond 302 noserver Location "/sp-msofba-completed"
} "/sp-msofba-completed" {
Successfully APM authenticated request MS-OFBA request detected. Sending MS-OFBA return response
ACCESS::respond 200 content "AuthenticatedGood Work, you are Authenticated" noserver
} "*/signout.aspx" {
SharePoint SignOut signature detected. Disconnect session and redirect to APM logout Page
ACCESS::respond 302 noserver Location "/vdesk/hangup.php3"
} "/_layouts/accessdenied.aspx" {
SharePoint AccessDenied signature detected.
if { [string tolower [URI::query [HTTP::uri] loginasanotheruser]] equals "true" } then {
SharePoint LoginAsAnotherUser request detected. Killing the APM session an sending redirect to www-root.
ACCESS::session remove
ACCESS::respond 302 noserver Location "/"
return
}
} default {
Let the authenticated request pass
}
}
when HTTP_RESPONSE {
if { [HTTP::header "Content-Type" ] contains "text/html" } then {
Insert persistent APM session cookie into HTTP response.
HTTP::header insert "Set-Cookie" "MRHSession_SP=$sessionid;path=/;secure"
HTTP::cookie expires "MRHSession_SP" 120 relative
}
if { $inject_session_cookie } then {
Insert APM session cookie into HTTP response.
HTTP::header insert "Set-Cookie" "MRHSession=$sessionid;path=/;secure"
set inject_session_cookie 0
}
}
Note: Your Clientless_Mode support can be easily included in the provided script. You just need to insert your existing code into the
script block and add the other iRule events. But be aware that the query to elseif { $authschema eq "legacy" } then {
exposes some security risks, since it can be used to bypass active account lockouts.[ACCESS::user getsid $user_key]
Update: Changed the session cookie injection mechanism.
Cheers, Kai