-
-
Save nddipiazza/ccb9c4490ca6c4c9d17c3b3fa7a6f4a7 to your computer and use it in GitHub Desktop.
<# | |
.Synopsis | |
Retrieve SPOIDCR cookie for SharePoint Online. | |
.Description | |
Authenticates to the sts and retrieves the SPOIDCR cookie for SharePoint Online. | |
Will use the custom IDP if one has been setup. | |
Optionally, can use integrated credentials (when integrated is set to true) with ADFS using the windowsmixed endpoint. | |
Results are formattable as XML, JSON, KEYVALUE, and by line. | |
Makes global variables avaiable at the end of the run. | |
$spoidcrl contains the SPOIDCRL cookie | |
.Example | |
The following returns the SPOIDCRL cookie value provided a username and password. | |
PS> .\spoidcrl.ps1 -url https://contoso.sharepoint.com -username [email protected] -password ABCDEFG | |
.Example | |
The following returns the SPOIDCRL cookie value using integrated windows credentials. Applies only to ADFS. | |
PS> .\spoidcrl.ps1 -url https://contoso.sharepoint.com/sites/site1 -integrated | |
.Example | |
The following saves the SPOIDCRL cookie value using integrated windows credentials. Applies only to ADFS. | |
PS> .\spoidcrl.ps1 -url https://contoso.sharepoint.com/sites/site1 -integrated -format "XML" | Out-File "c:\temp\spoidcr.txt" | |
.PARAMETER url | |
Tenant url (e.g. contoso.sharepoint.com) | |
.PARAMETER username | |
The username to login with. (e.g. [email protected] or [email protected]) | |
.PARAMETER password | |
The password to login with. | |
.PARAMETER integrated | |
Whether to use integrated credentials (user running PowerShell) instead of explicit credentials. | |
Needs to be supported by ADFS. | |
.PARAMETER format | |
How to format the output. Options include: XML, JSON, KEYVALUE | |
#> | |
[CmdletBinding()] | |
Param( | |
[Parameter(Mandatory=$true)] | |
[string]$url, | |
[Parameter(Mandatory=$false)] | |
[string]$username, | |
[Parameter(Mandatory=$false)] | |
[string]$password, | |
[Parameter(Mandatory=$false)] | |
[switch]$integrated = $false, | |
[Parameter(Mandatory=$false)] | |
[string]$format | |
) | |
$statusText = New-Object System.Text.StringBuilder | |
function log($info) | |
{ | |
if([string]::IsNullOrEmpty($info)) | |
{ | |
$info = "" | |
} | |
[void]$statusText.AppendLine($info) | |
} | |
try | |
{ | |
if (![uri]::IsWellFormedUriString($url, [UriKind]::Absolute)) | |
{ | |
throw "Parameter 'url' is not a valid URI." | |
} | |
else | |
{ | |
$uri = [uri]::new($url) | |
$tenant = $uri.Authority | |
Write-Host "Tenant is: $tenant" | |
} | |
if ($tenant.EndsWith("sharepoint.com", [System.StringComparison]::OrdinalIgnoreCase)) | |
{ | |
$msoDomain = "sharepoint.com" | |
} | |
else | |
{ | |
$msoDomain = $tenant | |
} | |
if ($integrated.ToBool()) | |
{ | |
[System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices") | out-null | |
[System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.AccountManagement") | out-null | |
$username = [System.DirectoryServices.AccountManagement.UserPrincipal]::Current.UserPrincipalName | |
} | |
elseif ([string]::IsNullOrWhiteSpace($username) -or [string]::IsNullOrWhiteSpace($password)) | |
{ | |
$credential = Get-Credential -UserName $username -Message "Enter credentials" | |
$username = $credential.UserName | |
$password = $credential.GetNetworkCredential().Password | |
} | |
$contextInfoUrl = $url.TrimEnd('/') + "/_api/contextinfo" | |
$getRealmUrl = "https://login.microsoftonline.com/GetUserRealm.srf" | |
$realm = "urn:federation:MicrosoftOnline" | |
$msoStsAuthUrl = "https://login.microsoftonline.com/rst2.srf" | |
$idcrlEndpoint = "https://$tenant/_vti_bin/idcrl.svc/" | |
Write-Host "ID CRL Endpoint: ${idcrlEndpoint}" | |
$username = [System.Security.SecurityElement]::Escape($username) | |
$password = [System.Security.SecurityElement]::Escape($password) | |
# Custom STS integrated authentication envelope format index info | |
# 0: message id - unique guid | |
# 1: custom STS auth url | |
# 2: realm | |
$customStsSamlIntegratedRequestFormat = "<?xml version=`"1.0`" encoding=`"UTF-8`"?><s:Envelope xmlns:s=`"http://www.w3.org/2003/05/soap-envelope`" xmlns:a=`"http://www.w3.org/2005/08/addressing`"><s:Header><a:Action s:mustUnderstand=`"1`">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action><a:MessageID>urn:uuid:{0}</a:MessageID><a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo><a:To s:mustUnderstand=`"1`">{1}</a:To></s:Header><s:Body><t:RequestSecurityToken xmlns:t=`"http://schemas.xmlsoap.org/ws/2005/02/trust`"><wsp:AppliesTo xmlns:wsp=`"http://schemas.xmlsoap.org/ws/2004/09/policy`"><wsa:EndpointReference xmlns:wsa=`"http://www.w3.org/2005/08/addressing`"><wsa:Address>{2}</wsa:Address></wsa:EndpointReference></wsp:AppliesTo><t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType><t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType></t:RequestSecurityToken></s:Body></s:Envelope>"; | |
# custom STS envelope format index info | |
# {0}: ADFS url, such as https://corp.sts.contoso.com/adfs/services/trust/2005/usernamemixed, its value comes from the response in GetUserRealm request. | |
# {1}: MessageId, it could be an arbitrary guid | |
# {2}: UserLogin, such as [email protected] | |
# {3}: Password | |
# {4}: Created datetime in UTC, such as 2012-11-16T23:24:52Z | |
# {5}: Expires datetime in UTC, such as 2012-11-16T23:34:52Z | |
# {6}: tokenIssuerUri, such as urn:federation:MicrosoftOnline, or urn:federation:MicrosoftOnline-int | |
$customStsSamlRequestFormat = "<?xml version=`"1.0`" encoding=`"UTF-8`"?><s:Envelope xmlns:s=`"http://www.w3.org/2003/05/soap-envelope`" xmlns:wsse=`"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd`" xmlns:saml=`"urn:oasis:names:tc:SAML:1.0:assertion`" xmlns:wsp=`"http://schemas.xmlsoap.org/ws/2004/09/policy`" xmlns:wsu=`"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd`" xmlns:wsa=`"http://www.w3.org/2005/08/addressing`" xmlns:wssc=`"http://schemas.xmlsoap.org/ws/2005/02/sc`" xmlns:wst=`"http://schemas.xmlsoap.org/ws/2005/02/trust`"><s:Header><wsa:Action s:mustUnderstand=`"1`">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</wsa:Action><wsa:To s:mustUnderstand=`"1`">{0}</wsa:To><wsa:MessageID>{1}</wsa:MessageID><ps:AuthInfo xmlns:ps=`"http://schemas.microsoft.com/Passport/SoapServices/PPCRL`" Id=`"PPAuthInfo`"><ps:HostingApp>Managed IDCRL</ps:HostingApp><ps:BinaryVersion>6</ps:BinaryVersion><ps:UIVersion>1</ps:UIVersion><ps:Cookies></ps:Cookies><ps:RequestParams>AQAAAAIAAABsYwQAAAAxMDMz</ps:RequestParams></ps:AuthInfo><wsse:Security><wsse:UsernameToken wsu:Id=`"user`"><wsse:Username>{2}</wsse:Username><wsse:Password>{3}</wsse:Password></wsse:UsernameToken><wsu:Timestamp Id=`"Timestamp`"><wsu:Created>{4}</wsu:Created><wsu:Expires>{5}</wsu:Expires></wsu:Timestamp></wsse:Security></s:Header><s:Body><wst:RequestSecurityToken Id=`"RST0`"><wst:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</wst:RequestType><wsp:AppliesTo><wsa:EndpointReference> <wsa:Address>{6}</wsa:Address></wsa:EndpointReference></wsp:AppliesTo><wst:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</wst:KeyType></wst:RequestSecurityToken></s:Body></s:Envelope>" | |
# mso envelope format index info (Used for custom STS + MSO authentication) | |
# 0: custom STS assertion | |
# 1: mso endpoint | |
$msoSamlRequestFormat = "<?xml version=`"1.0`" encoding=`"UTF-8`"?><S:Envelope xmlns:S=`"http://www.w3.org/2003/05/soap-envelope`" xmlns:wsse=`"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd`" xmlns:wsp=`"http://schemas.xmlsoap.org/ws/2004/09/policy`" xmlns:wsu=`"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd`" xmlns:wsa=`"http://www.w3.org/2005/08/addressing`" xmlns:wst=`"http://schemas.xmlsoap.org/ws/2005/02/trust`"><S:Header><wsa:Action S:mustUnderstand=`"1`">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</wsa:Action><wsa:To S:mustUnderstand=`"1`">https://login.microsoftonline.com/rst2.srf</wsa:To><ps:AuthInfo xmlns:ps=`"http://schemas.microsoft.com/LiveID/SoapServices/v1`" Id=`"PPAuthInfo`"><ps:BinaryVersion>5</ps:BinaryVersion><ps:HostingApp>Managed IDCRL</ps:HostingApp></ps:AuthInfo><wsse:Security>{0}</wsse:Security></S:Header><S:Body><wst:RequestSecurityToken xmlns:wst=`"http://schemas.xmlsoap.org/ws/2005/02/trust`" Id=`"RST0`"><wst:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</wst:RequestType><wsp:AppliesTo><wsa:EndpointReference><wsa:Address>{1}</wsa:Address></wsa:EndpointReference></wsp:AppliesTo><wsp:PolicyReference URI=`"MBI`"></wsp:PolicyReference></wst:RequestSecurityToken></S:Body></S:Envelope>" | |
# mso envelope format index info (Used for MSO-only authentication) | |
# 0: mso endpoint | |
# 1: username | |
# 2: password | |
$msoSamlRequestFormat2 = "<?xml version=`"1.0`" encoding=`"UTF-8`"?><S:Envelope xmlns:S=`"http://www.w3.org/2003/05/soap-envelope`" xmlns:wsse=`"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd`" xmlns:wsp=`"http://schemas.xmlsoap.org/ws/2004/09/policy`" xmlns:wsu=`"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd`" xmlns:wsa=`"http://www.w3.org/2005/08/addressing`" xmlns:wst=`"http://schemas.xmlsoap.org/ws/2005/02/trust`"><S:Header><wsa:Action S:mustUnderstand=`"1`">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</wsa:Action><wsa:To S:mustUnderstand=`"1`">{0}</wsa:To><ps:AuthInfo xmlns:ps=`"http://schemas.microsoft.com/LiveID/SoapServices/v1`" Id=`"PPAuthInfo`"><ps:BinaryVersion>5</ps:BinaryVersion><ps:HostingApp>Managed IDCRL</ps:HostingApp></ps:AuthInfo><wsse:Security><wsse:UsernameToken wsu:Id=`"user`"><wsse:Username>{1}</wsse:Username><wsse:Password>{2}</wsse:Password></wsse:UsernameToken></wsse:Security></S:Header><S:Body><wst:RequestSecurityToken xmlns:wst=`"http://schemas.xmlsoap.org/ws/2005/02/trust`" Id=`"RST0`"><wst:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</wst:RequestType><wsp:AppliesTo><wsa:EndpointReference><wsa:Address>sharepoint.com</wsa:Address></wsa:EndpointReference></wsp:AppliesTo><wsp:PolicyReference URI=`"MBI`"></wsp:PolicyReference></wst:RequestSecurityToken></S:Body></S:Envelope>" | |
function Invoke-HttpPost($endpoint, $body, $headers, $session) | |
{ | |
log | |
log "Invoke-HttpPost" | |
log "url: $endpoint" | |
log "post body: $body" | |
$params = @{} | |
$params.Headers = $headers | |
$params.uri = $endpoint | |
$params.Body = $body | |
$params.Method = "POST" | |
$params.WebSession = $session | |
$response = Invoke-WebRequest @params -ContentType "application/soap+xml; charset=utf-8" -UseDefaultCredentials -UserAgent ([string]::Empty) | |
$content = $response.Content | |
return $content | |
} | |
# Get saml Assertion value from the custom STS | |
function Get-AssertionCustomSts($customStsAuthUrl) | |
{ | |
log | |
log "Get-AssertionCustomSts" | |
$messageId = [guid]::NewGuid() | |
$created = [datetime]::UtcNow.ToString("o", [System.Globalization.CultureInfo]::InvariantCulture) | |
$expires = [datetime]::UtcNow.AddMinutes(10).ToString("o", [System.Globalization.CultureInfo]::InvariantCulture) | |
if ($integrated.ToBool()) | |
{ | |
log "integrated" | |
$customStsAuthUrl = $customStsAuthUrl.ToLowerInvariant().Replace("/usernamemixed","/windowstransport") | |
log $customStsAuthUrl | |
$requestSecurityToken = [string]::Format($customStsSamlIntegratedRequestFormat, $messageId, $customStsAuthUrl, $realm) | |
log $requestSecurityToken | |
} | |
else | |
{ | |
log "not integrated" | |
$requestSecurityToken = [string]::Format($customStsSamlRequestFormat, $customStsAuthUrl, $messageId, $username, $password, $created, $expires, $realm) | |
log $requestSecurityToken | |
} | |
[xml]$customStsXml = Invoke-HttpPost $customStsAuthUrl $requestSecurityToken | |
return $customStsXml.Envelope.Body.RequestSecurityTokenResponse.RequestedSecurityToken.Assertion.OuterXml | |
} | |
function Get-BinarySecurityToken($customStsAssertion, $msoSamlRequestFormatTemp) | |
{ | |
log | |
log "Get-BinarySecurityToken" | |
if ([string]::IsNullOrWhiteSpace($customStsAssertion)) | |
{ | |
log "using username and password" | |
$msoPostEnvelope = [string]::Format($msoSamlRequestFormatTemp, $msoDomain, $username, $password) | |
} | |
else | |
{ | |
log "using custom sts assertion" | |
$msoPostEnvelope = [string]::Format($msoSamlRequestFormatTemp, $customStsAssertion, $msoDomain) | |
} | |
$msoContent = Invoke-HttpPost $msoStsAuthUrl $msoPostEnvelope | |
# Get binary security token using regex instead of [xml] | |
# Using regex to workaround PowerShell [xml] bug where hidden characters cause failure | |
[regex]$regex = "BinarySecurityToken Id=.*>([^<]+)<" | |
$match = $regex.Match($msoContent).Groups[1] | |
return $match.Value | |
} | |
function Get-SPOIDCRLCookie($msoBinarySecurityToken) | |
{ | |
log | |
log "Get-SPOIDCRLCookie" | |
log | |
log "BinarySecurityToken: $msoBinarySecurityToken" | |
$binarySecurityTokenHeader = [string]::Format("BPOSIDCRL {0}", $msoBinarySecurityToken) | |
$params = @{uri=$idcrlEndpoint | |
Method="GET" | |
Headers = @{} | |
} | |
$params.Headers["Authorization"] = $binarySecurityTokenHeader | |
$params.Headers["X-IDCRL_ACCEPTED"] = "t" | |
$resonse = Invoke-WebRequest @params -UserAgent ([string]::Empty) | |
$cookie = $resonse.BaseResponse.Cookies["SPOIDCRL"] | |
return $cookie | |
} | |
# Retrieve the configured STS Auth Url (ADFS, PING, etc.) | |
function Get-UserRealmUrl($getRealmUrl, $username) | |
{ | |
log | |
log "Get-UserRealmUrl" | |
log "url: $getRealmUrl" | |
log "username: $username" | |
$body = "login=$username&xml=1" | |
$response = Invoke-WebRequest -Uri $getRealmUrl -Method POST -Body $body -UserAgent ([string]::Empty) | |
return ([xml]$response.Content).RealmInfo.STSAuthURL | |
} | |
[System.Net.ServicePointManager]::Expect100Continue = $true | |
#1 Get custom STS auth url | |
$customStsAuthUrl = Get-UserRealmUrl $getRealmUrl $username | |
if ($customStsAuthUrl -eq $null) | |
{ | |
#2 Get binary security token from the MSO STS by passing the SAML <Assertion> xml | |
$customStsAssertion = $null | |
$msoBinarySecurityToken = Get-BinarySecurityToken $customStsAssertion $msoSamlRequestFormat2 | |
} | |
else | |
{ | |
#2 Get SAML <Assertion> xml from custom STS | |
$customStsAssertion = Get-AssertionCustomSts $customStsAuthUrl | |
#3 Get binary security token from the MSO STS by passing the SAML <Assertion> xml | |
$msoBinarySecurityToken = Get-BinarySecurityToken $customStsAssertion $msoSamlRequestFormat | |
} | |
#3/4 Get SPOIDRCL cookie from SharePoint site by passing the binary security token | |
# Save cookie and reuse with multiple requests | |
$idcrl = $null | |
$idcrl = Get-SPOIDCRLCookie $msoBinarySecurityToken | |
if ([string]::IsNullOrEmpty($format)) | |
{ | |
$format = [string]::Empty | |
} | |
else | |
{ | |
$format = $format.Trim().ToUpperInvariant() | |
} | |
$Global:spoidcrl = $idcrl | |
if ($format -eq "XML") | |
{ | |
Write-Output ([string]::Format("<SPOIDCRL>{0}</SPOIDCRL>", $idcrl.Value)) | |
} | |
elseif ($format -eq "JSON") | |
{ | |
Write-Output ([string]::Format("{{`"SPOIDCRL`":`"{0}`"}}", $idcrl.Value)) | |
} | |
elseif ($format.StartsWith("KEYVALUE") -or $format.StartsWith("NAMEVALUE")) | |
{ | |
Write-Output ("SPOIDCRL:" + $idcrl.Value) | |
} | |
else | |
{ | |
Write-Output $idcrl.Value | |
} | |
} | |
catch | |
{ | |
log $error[0] | |
"ERROR:" + $statusText.ToString() | |
} | |
@kasinaat , did you find a solution ? I'm trying to get it too
@rlodev67
We have to use ClientId, ClientSecret and a client certificate to generate a JWT Assertion, with that assertion we will be able to get an access_token from microsoft, Legacy authentication is completely disabled and Modern authentication is the only way to go
Thanks, I have already an access_token which i'm using for CSOM access, but how can I get the SPOIDCRL cookie from that ?
I'm getting:
PS C:\temp> .\spoidcrl.ps1 -url https://xxxxxxxxxxxxxxxxxxxx -integrated
Tenant is: xxxxxxxxxxxxxxxxxxxxxxxx
ID CRL Endpoint: https://xxxxxxxxxxxxxxxxxxxxxxxxx/_vti_bin/idcrl.svc/
ERROR:
Get-UserRealmUrl
url: https://login.microsoftonline.com/GetUserRealm.srf
username: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
The underlying connection was closed: An unexpected error occurred on a send.
Any help would be appreciated.
How to achieve the same is Legacy authentication is disabled in sharepoint admin center?, I am trying to do that but getting 401 in the Get-SPOIDCRLCookie function.