ADFS PowerShell: Scripting Web API (Add-AdfsWebApiApplication) with RuleTemplate in IssuanceTransformRules - powershell

I've defined an ADFS Application Group using the ADFS MMC. I'd like to create a script for deployment. I've successfully scripted using New-AdfsApplicationGroup and Add-AdfsNativeClientApplication. Next I'd like to script the Web API. Looking at the output of Get-AdfsWebApiApplication I see the following IssuanceTransformRules. The rule is named and references a template.
#RuleTemplate = "LdapClaims"
#RuleName = "2"
c:[Type ==
"http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname",
Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = ("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"), query =
";mail,sAMAccountName,userPrincipalName;{0}", param = c.Value);
I scripted this as:
Add-AdfsWebApiApplication -Name "My Web API" -AllowedClientTypes 6 -ApplicationGroupIdentifier "MyApp" -IssueOAuthRefreshTokensTo 2 -TokenLifetime 7 -Identifier {https://apphost/myapp/api/} -IssuanceTransformRules '#RuleTemplate = "LdapClaims", #RuleName = "2", c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"] => issue(store = "Active Directory", types = ("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"), query = ";mail,sAMAccountName,userPrincipalName;{0}", param = c.Value);'
This results in the following error.
Parser error: 'POLICY0030: Syntax error, unexpected COMMA, expecting
one of the following: O_SQ_BRACKET IDENTIFIER NOT AT IMPLY .' At
line:1 char:1
+ Add-AdfsWebApiApplication -Name "My Web API" -AllowedClientTypes ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo :InvalidData: (#RuleTemplate =...ram = c.Value);:String) [Add-AdfsWebApiApplication],
PolicyValidationException
+ FullyQualifiedErrorId: POLICY0002.Microsoft.IdentityServer.Management.Commands.Add-AdfsWebApiApplicationCommand
Removing both #RuleTemplate and #RuleName, the following executes successfully but produces a custom rule that cannot be edited using the graphical template which provides dropdown lists for LDAP Attributes and Outgoing Claim Types.
Add-AdfsWebApiApplication -Name "My Web API" -AllowedClientTypes 6 -ApplicationGroupIdentifier "MyApp" -IssueOAuthRefreshTokensTo 2 -TokenLifetime 7 -Identifier {https://apphost/myapp/api/} -IssuanceTransformRules 'c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"] => issue(store = "Active Directory", types = ("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"), query = ";mail,sAMAccountName,userPrincipalName;{0}", param = c.Value);'
Might someone suggest a way to include a name or template in the script?

What if you include your transform claim data in a variable and then reference variable in your cmdlet?
$transformRules = #"
#RuleTemplate = "LdapClaims"
#RuleName = "2"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = ("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"), query = ";mail,sAMAccountName,userPrincipalName;{0}", param = c.Value);
"#
Add-AdfsWebApiApplication -Name "My Web API" -AllowedClientTypes 6 -ApplicationGroupIdentifier "MyApp" -IssueOAuthRefreshTokensTo 2 -TokenLifetime 7 -Identifier {https://apphost/myapp/api/} -IssuanceTransformRules $transformRules

Related

EWS and AutoDiscoverURL error using Azure AD Certificate with Powershell

I've tried with and without Secret ID, and now with a self-signed Certificate and I keep getting the same error:
Exception calling "AutodiscoverUrl" with "2" argument(s): "The
expected XML node type was XmlDeclaration, but the actual type is
Element."
My PowerShell script:
$TenantId = "blahblah"
$AppClientId="blahblah"
$EDIcertThumbPrint = "blahblah"
$EDIcert = get-childitem Cert:\CurrentUser\My\$EDIcertThumbPrint
$MsalParams = #{
ClientId = $AppClientId
TenantId = $TenantId
ClientCertificate = $EDIcert
Scopes = "https://outlook.office.com/.default"
}
$MsalResponse = Get-MsalToken #MsalParams
$EWSAccessToken = $MsalResponse.AccessToken
Import-Module 'C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll'
#Provide the mailbox id (email address) to connect via AutoDiscover
$MailboxName ="email#myemaildomain.com.au"
$ews = [Microsoft.Exchange.WebServices.Data.ExchangeService]::new()
$ews.Credentials = [Microsoft.Exchange.WebServices.Data.OAuthCredentials]$EWSAccessToken
$ews.Url = "https://outlook.office365.com/EWS/Exchange.asmx"
$ews.AutodiscoverUrl($MailboxName,{$true})
I've searched that error message everywhere, and I am not getting anywhere. The error doesn't make sense, because I am not referring to XML in any way - unless it's embedded inside the EWS?
The only time this works is when I don't use either a Secret ID nor a Certificate, but the Token only lasts 1 hour! I need to make this automatic, so I can get into my mailbox and extract files from emails.
Thanks
UPDATE
So I've removed the AutoDiscoverUrl() and I now getting another error:
Exception calling "FindItems" with "2" argument(s): "The request
failed. The remote server returned an error: (403) Forbidden."
Trace log:
The token contains not enough scope to make this call.";error_category="invalid_grant"
But why when I have an Oauth token!?
My code in trying to open the "Inbox":
$results = $ews.FindItems(
"Inbox",
( New-Object Microsoft.Exchange.WebServices.Data.ItemView -ArgumentList 100 )
)
$MailItems = $results.Items | where hasattachments
AutoDiscoverv1 doesn't support the client credentials flow so you need to remove the line
$ews.AutodiscoverUrl($MailboxName,{$true})
It's redundant anyway because your already setting the EWS endpoint eg
$ews.Url = "https://outlook.office365.com/EWS/Exchange.asmx"
The only time that endpoint would change is if you had mailbox OnPrem in a hybrid environment and there are other ways you can go about detecting that such as autodiscoverv2.

DSC for initialising and formatting disks

I need to format a disk for servers using DSC. I tried using the below from
https://blogs.msdn.microsoft.com/timomta/2016/04/23/how-to-use-powershell-dsc-to-prepare-a-data-drive-on-an-azure-vm/#comment-1865
But it doesnt work as it doesn't seem to be complete, I get errors
"+ xWaitforDisk Disk2 + ~~~~~~~~~~~~ Resource 'xWaitForDisk' requires
that a value of type 'String' be provided for property 'DiskId'.
At line:18 char:1 + DiskNumber = 2 + ~~~~~~~~~~ The member
'DiskNumber' is not valid. Valid members are 'DependsOn', 'DiskId',
'DiskIdType', 'PsDscRunAsCredential', 'RetryCount',
'RetryIntervalSec'. "
Configuration DataDisk
{
Import-DSCResource -ModuleName xStorage
Node localhost
{
xWaitforDisk Disk2
{
DiskNumber = 2
RetryIntervalSec = 60
Count = 60
}
xDisk FVolume
{
DiskNumber = 2
DriveLetter = 'F'
FSLabel = 'Data'
}
}
You need to replace DiskNumber with DiskID.
Take a look at the examples on GitHub https://github.com/PowerShell/StorageDsc/tree/dev/Modules/StorageDsc/Examples/Resources
You can find the DiskId with powershell use the command: Get-Disk

AWS Cloudfront files' invalidation via REST API and Powershell

I'm trying to write a PowerShell script to invalidate an object of AWS Cloudfront distribution (just a specific file), and not sure how to produce the "signed URL" they're asking for.
My code so far is:
$authPref = "AWS4-HMAC-SHA256"
$AWSAccessKey = "xxx"
$AWSSecretKey = "xxx"
$awsDateOnly = (Get-Date).AddHours(-3).ToString("yyyyMMdd")
$awsRegion = "us-east-1"
$awsServiceName = "cloudfront"
$awsRequestType = "aws4_request"
$stringToSign = $authPref + " " + $awsCallerReference + " " + $awsDateOnly + "/" + $awsRegion + "/" + $awsServiceName + "/" + $awsRequestType + " SOME_STRING_NOT_SURE_WHAT"
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($stringToSign)
$awsHMAC = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($AWSSecretKey))
$awsHMAC = [Convert]::ToBase64String($awsHMAC)
$awsSignedToken = $authPref + " Credential=" + $AWSAccessKey + "/" + $awsDateOnly + "/" + $awsRegion + "/" + $awsServiceName + "/" + $awsRequestType + ", SignedHeaders=content-type;host;x-amz-date, Signature=" + $awsHMAC
#POST /2017-03-25/distribution/$awsDistributionID/invalidation HTTP/1.1
$awsDistributionID = "xxx"
$awsCallerReference = (Get-Date).AddHours(-3).ToString("yyyyMMdd'T'HHmmss'Z'")
$invalidateObjectXML = #"
<?xml version="1.0" encoding="UTF-8"?>
<InvalidationBatch xmlns="http://cloudfront.amazonaws.com/doc/2017-03-25/">
<CallerReference>$awsCallerReference</CallerReference>
<Paths>
<Items>
<Path>/</Path>
</Items>
<Quantity>1</Quantity>
</Paths>
</InvalidationBatch>
"#
[xml]$invalidateObjectXML = $invalidateObjectXML
$awsCFuri = "https://cloudfront.amazonaws.com/2017-03-25/distribution/$awsDistributionID/invalidation"
Invoke-WebRequest -Method POST `
-Uri $awsCFuri `
-Headers #{"content-type"="text/xml";
"x-amz-date"="$awsCallerReference";
"authorization"="$awsSignedToken";
"host"="cloudfront.amazonaws.com"} `
-Body $invalidateObjectXML
The response is:
<ErrorResponse xmlns="http://cloudfront.amazonaws.com/doc/2017-03-25/"><Error><Type>Sender</Type><Code>SignatureDoesNotMatch</Code><Message>The request
signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation
for details.
The Canonical String for this request should have been
'POST
/2017-03-25/distribution/blabla/invalidation
content-type:text/xml
host:cloudfront.amazonaws.com
x-amz-date:20170503T203650Z
content-type;host;x-amz-date
blabla'
The String-to-Sign should have been
'AWS4-HMAC-SHA256
20170503T203650Z
20170503/us-east-1/cloudfront/aws4_request
blabla'
</Message></Error><RequestId>123-123</RequestId></ErrorResponse>
At line:1 char:1
So obviously I'm doing something wrong with the signed URL string that I do, but what it is?
Couldn't find any examples on the internet (not AWS docs nor any other blog) that demonstrates it in Powershell.
Thanks
AWS has developed a PowerShell module to interact with the AWS API called the AWS Tools for PowerShell. This module specifically handles request building and signing for you, so this method of calling to the raw API becomes unnecessary.
You can use this specifically to invalidate objects in a CloudFront distribution with the New-CFInvalidation cmdlet. Write the paths you want to invalidate to the Paths_Item parameter.
Signature:
New-CFInvalidation
-DistributionId <String>
-InvalidationBatch_CallerReference <String>
-Paths_Item <String[]>
-Paths_Quantity <Int32>
-Force <SwitchParameter>
Further Reading
AWS Documentation - Invalidating Objects and Displaying Information about Invalidations
AWS Documentation - New-CFInvalidation Cmdlet

AD FS email claim not found

I have a web app. I'm trying to get it to authenticate against a Win2012 R2 ADFS server.
I have the relying party set up, get redirected, sign in, then redirected back to the app as a failed request.
In the event log I have this:
MSIS7070: The SAML request contained a NameIDPolicy that was not satisfied by the issued token. Requested NameIDPolicy: AllowCreate: True Format: urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress SPNameQualifier: . Actual NameID properties: null.
If I read this right, the webapp is asking for urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress but that policy isn't found for the relying party.
Under the relying party, I have two rules:
# get email address from active directory
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory",
types = ("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"), query = ";mail;{0}", param = c.Value);
rule 2
transform email address to nameid/email
c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]
=> issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
Issuer = c.Issuer,
OriginalIssuer = c.OriginalIssuer,
Value = c.Value,
ValueType = c.ValueType,
Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"]
= "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress");
I've double checked and made sure that the formats match, but I'm stuck on the error messages.

Ability to set CertificateID for LCM with February powershell 5

I'm trying to update my DSC deployment to now use partial configurations to break up the configuration. For that I need to now use a pull process instead of push.
When I try to apply the configuration for the LCM which looks something like:
[DscLocalConfigurationManager()]
Configuration CreateGESService
{
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullorEmpty()]
[PsCredential] $InstallCredential,
[Parameter(Mandatory=$true)]
[ValidateNotNullorEmpty()]
[PsCredential] $RunCredential
)
Node $AllNodes.NodeName
{
$hostVersion = (get-host).Version
# changed how the possible values for debugMode in the February build
if (($hostVersion.Major -ge 5) -and ($hostVersion.Minor -ge 0) -and ($hostVersion.Build -ge 9842)){
$debugMode = 'All'
}
else{
$debugMode = $true
}
#setup the localConfigManager
Settings
{
#CertificateID = $node.Thumbprint
# slower performance - and only available WMF5
# now we need to kill the dsc
DebugMode = $debugMode
ConfigurationMode = 'ApplyAndAutoCorrect'
ConfigurationModeFrequencyMins = '15'
AllowModuleOverwrite = $true
RefreshMode = 'Push'
ConfigurationID = $node.ConfigurationID
}
PartialConfiguration GetEventStoreConfiguration {
Description = "Contains the stuff for GetEventStore Being Installed"
ConfigurationSource = "[ConfigurationRepositoryShare]ConfigSource"
RefreshMode = "Pull"
}
PartialConfiguration ExternalIntegrationConfiguration{
Description = "Contains the stuff for External Integration"
ConfigurationSource = "[ConfigurationRepositoryShare]ConfigSource"
DependsOn = '[PartialConfiguration]GetEventStoreConfiguration'
RefreshMode = "Pull"
}
PartialConfiguration ServeGroupSpike{
Description = "Contains the stuff for External Integration"
ConfigurationSource = "[ConfigurationRepositoryShare]ConfigSource"
DependsOn = '[PartialConfiguration]ExternalIntegrationConfiguration'
RefreshMode = "Pull"
}
ConfigurationRepositoryShare ConfigSource{
SourcePath = "\\someServer\Shared\dscService\Configuration"
Credential = $InstallCredential
}
ResourceRepositoryShare ResourceSource{
SourcePath = "\\someServer\Shared\dscService\Resources"
Credential = $InstallCredential
}
}
If I try to include the CertificateID I get an error like:
The property CertificateID of metaconfiguration is not compatible with the current version 2.0.0 of the configuration
document. This property only works with version greater than or equal to 1.0.0 . In case the version is greater, then
the property MinimumCompatibleVersion should be set to atleast 1.0.0 . Set these properties in the
OMI_ConfigurationDocument instance in the document and try again.
+ CategoryInfo : InvalidArgument: (root/Microsoft/...gurationManager:String) [], CimException
+ FullyQualifiedErrorId : MI RESULT 4
+ PSComputerName : SGSpike-Main
Naturally when the Configuration is attempted to be applied it can't decrypt the credentials passed, and I get an error in the event view like:
Job {B37D5239-EDBA-11E4-80C2-00155D9ACA1F} :
WarningMessage An error occured while applying the partial configuration [PartialConfiguration]ExternalIntegrationConfiguration. The error message is :
The Local Configuration Manager is not configured with a certificate. Resource '[File]GpgProgram' in configuration 'ExternalIntegrationConfiguration' cannot be processed..
Any ideas how to do this? I had this working with the certificateID when I was using a single configuration in a push model.
Even in the April 2015 drop the problem still seems to exist. Further diagnosis shows that you can:
Not use partial configurations
Not use a certificate to encrypt credentials
Opened an issue on connect (with some more details) at https://connect.microsoft.com/PowerShell/Feedback/Details/1292678