Office 2013 with ADAL not working with Single Sign-On

I am currently testing out Office 2013 with ADAL which is currently in preview. With ADAL, the Office applications support “Modern Authentication” which means web redirects instead of using the old basic authentication and “proxying credentials” through Office 365. I followed the guidance and enabled ADAL. However, despite of using ADFS and having the adfs website added as an “intranett site” in security settings in IE, all I got was forms based authentication and not single sign-on as I expected. I contacted the Microsoft product group and verified that this was indeed supposed to work and was one of the primary use cases.

If you enable the TCOTrace registry key, the %temp%\outlook.exe.txt logfile is created and here I found the following entry:

ADAL: message=’Could not discover endpoint for Integrate Windows Authentication. Check your ADFS settings. It should support Integrate Widows Authentication for WS-Trust 1.3.’, additionalInformation=’Authority: https://login.windows.net/common

To fix this, you need to enable an ADFS endpoint that is disabled by default. To do this you need to run the following PowerShell cmdlet and restart the ADFS service on all servers in the farm.


Enable-AdfsEndpoint -TargetAddressPath "/adfs/services/trust/13/windowstransport"

Now it should work, with ADAL giving you perfect SSO from your Office applications.

Another bug

I also encountered a bug that Microsoft is fixing (also verified after contacting the product group) in the April update. If you find a log line saying CheckADUser: Not AD user found in the log file, even though you are a domain user, you have encountered this bug. To fix, close all Office apps and delete the following registry key below and try again: HKCU\Software\Microsoft\Office\15.0\Common\Identity\SignedOutADUser

After deleting the registry key, ADAL should not try Integrated Windows Authentication instead of Forms Based Authentication.

Using your PowerShell profile for something very useful

Have you ever found yourself writing the same PowerShell code over and over, thinking “there should be a built-in function for this”. Here is my trick for an even better PowerShell day! First I’ll show you how to create a PowerShell profile where you can define all of our favorite methods, and then I’ll show you how to use it on many computers, as you will probably want this on your servers as well as your desktop.

Start by opening a PowerShell and type $profile. This default variable contains a path to your PowerShell profile, usually located in the Documents\WindowsPowerShell, which does not exist by default. Run the following two lines to create the folder, and create an empty file.

mkdir (Split-Path $profile) -ErrorAction SilentlyContinue;
if(!(Test-Path $profile))
{
	Set-Content -Path $profile -Value ""
}

After running these you have an empty profile. Use your favorite editor to edit the file.

# PS> ise $profile

The code inside this file will run each time your start a new PowerShell. Here you can define your own methods. What makes this very usefull is the possibility to create a method to download your PowerShell profile from the internet. Here is an example of such a function:

# Function to update the powershellprofile from the internet
function Update-PowerShellProfile() {
    [CmdletBinding()]
    Param()
    Write-Verbose "Updating PowerShell profile"

    if(!(Test-Path (Split-Path $profile))) {
        Write-Verbose ("Profile path did not exist, creating {0}" -f (Split-Path $profile))
        mkdir (Split-Path $profile)
    }

    Write-Debug "Creating System.Net.WebClient"
    $wc = New-Object System.Net.WebClient
    Write-Debug "Downloading file http://pastebin.com/raw.php?i=tdySrDgz"
    $wc.DownloadFile("http://pastebin.com/raw.php?i=tdySrDgz", $profile)

    Write-Output "Reload profile with the cmdlet:  . `$profile"
}

Basically it downloads a some stuff from pastebin and puts into the PowerShell profile. After this, you can either open a new PowerShell to run the profile again, or you can type “. $profile” to re-load the profile.

Here is an example of a full profile (a subset of methods I have in mine). I have my own PowerShell profile hosted in my Dropbox folder, but you choose wherever you want, just change the Update-PowerShellProfile method.


function Connect-ExchangeOnline{
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$True,Position=0)]
        [System.Management.Automation.PSCredential]$Credentials
    )
    $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -Authentication Basic -AllowRedirection -Credential $Credentials
    Import-PSSession $session -DisableNameChecking
}

function Disconnect-ExchangeOnline {
    [CmdletBinding()]
    Param()
    Get-PSSession | ?{$_.ComputerName -like "*outlook.com"} | Remove-PSSession
}

# Function to update the powershellprofile from the internet
function Update-PowerShellProfile() {
    [CmdletBinding()]
    Param()
    Write-Verbose "Updating PowerShell profile"

    if(!(Test-Path (Split-Path $profile))) {
        Write-Verbose ("Profile path did not exist, creating {0}" -f (Split-Path $profile))
        mkdir (Split-Path $profile)
    }

    Write-Debug "Creating System.Net.WebClient"
    $wc = New-Object System.Net.WebClient
    Write-Debug "Downloading file http://pastebin.com/raw.php?i=tdySrDgz"
    $wc.DownloadFile("http://pastebin.com/raw.php?i=tdySrDgz", $profile)

    Write-Output "Reload profile with the cmdlet:  . `$profile"
}

# Set the PowerShell prompt to PS>
function prompt{
    Write-Host -ForegroundColor Red "PS" -NoNewline
    Write-Host -ForegroundColor White -NoNewline ">"
    return " "
}



function ConvertTo-Base64
{
    [CmdletBinding(DefaultParameterSetName='String')]
    [OutputType([String])]
    Param
    (
        # String to convert to base64
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   ValueFromRemainingArguments=$false,
                   Position=0,
                   ParameterSetName='String')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]
        $String,

        # Param2 help description
        [Parameter(ParameterSetName='ByteArray')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [byte[]]
        $ByteArray
    )

    if($String) {
        return [System.Convert]::ToBase64String(([System.Text.Encoding]::UTF8.GetBytes($String)));
    } else {
        return [System.Convert]::ToBase64String($ByteArray);
    }
}



function ConvertFrom-Base64 {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$True,
                   Position=0,
                   ValueFromPipeline=$true)]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]
        $Base64String
    )

    return [System.Text.Encoding]::UTF8.GetString(([System.Convert]::FromBase64String($Base64String)));
}






function Split-String
{
    [CmdletBinding()]
    [OutputType([string[]])]
    Param
    (
        # The input string object
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   Position=0)]
        [String] $InputObject,

        # Split delimiter
        [Parameter(Mandatory=$false,
                   ValueFromPipeline=$false,
                   Position=1)]
        [String] $Delimiter = "`n",

        # Do trimming or not
        [Parameter(Mandatory=$false,
                   ValueFromPipeline=$false,
                   Position=2)]
        [Boolean] $Trim = $true

    )

    if($Trim) {
        return $InputObject -split $Delimiter | foreach{$_.Trim()}
    } else {
        return $InputObject -split $Delimiter
    }
}




function ConvertFrom-ImmutableID
{
    [CmdletBinding()]
    [OutputType([GUID])]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$false,
                   ValueFromPipeline=$true,
                   Position=0)]
        $ImmutableID
    )

    return [guid]([system.convert]::frombase64string($ImmutableID) )
}




function New-ObjectFromHashmap
{
    [CmdletBinding()]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   Position=0)]
        $Hashmap
    )

    Begin
    {
    }
    Process
    {
        New-Object -TypeName PSCustomObject -Property $Hashmap
    }
    End
    {
    }
}

Then for each new server you are working on, just find a way to bring the Update-PowerShellProfile method, run it and you have the same profile everywhere, such as my Connect-ExchangeOnline method or the Split-String method.

Have fun!

Virtual hosting with Apache – the good way

There are so many amazingly bad guides to Apache and virtual hosting, so i decided to create a good one. This guide uses Apache2 running om Debian 6. I will not cover installation and stuff. Also, I cut right to the chase.

First, the NameVirtualHost property should just be declared once, and ports.conf is a good place to have it.

/etc/apache2/ports.conf

NameVirtualHost *:80
Listen 80

Second, do not place all virtual hosts in a single file, that’s not very dynamic. Look at this:

# ls /etc/apache2/sites-*
/etc/apache2/sites-available:
total 8
dr-xr-x--- 2 root           www-data     3896 Jun 26 15:33 .
dr-x------ 5 www-data        www-data     3896 Jun  8 13:15 ..
-rwxr-x--- 1 root           www-data     569  Apr 11 21:51 default
-rwxr-x--- 1 root           www-data     569  Apr 19 11:40 sub1.example.org
-rwxr-x--- 1 root           www-data     569  Apr 19 11:41 sub2.example.org
-rwxr-x--- 1 root           www-data     569  Jun 26 15:25 goodworkaround.com

/etc/apache2/sites-enabled:
total 0
dr-xr-x--- 2 www-data  www-data 3896 Jun 26 15:33 .
dr-x------ 5 www-data  www-data 3896 Jun  8 13:15 ..
lrwxrwxrwx 1 root   root  26 Apr 11 21:52 000-default -> ../sites-available/default
lrwxrwxrwx 1 root   root  41 Apr 19 11:49 sub1.example.org -> ../sites-available/sub1.example.org
lrwxrwxrwx 1 root   root  41 Apr 19 11:50 sub2.example.org -> ../sites-available/sub2.example.org
lrwxrwxrwx 1 root   root  37 Jun 26 15:29 goodworkaround.com -> ../sites-available/goodworkaround.com

So what am I doing that no one else is doing? I am symlinking, and I am splitting each domain or subdomain into separate files. Just use place all the domains in the sites-available folder, and symlink it from sites-enabled. This makes it easy to disable sites temporary, by just removing the symlink and reloading apache. Lets take a look one of those files.

/etc/apache2/sites-available/goodworkaround.com

<VirtualHost *:80>
        ServerAdmin webmaster@goodworkaround.com
        ServerName goodworkaround.com
        # ServerAlias www.goodworkaround.com

        DocumentRoot /home/mariussm/websites/goodworkaround.com

        <Directory />
                Options FollowSymLinks
                AllowOverride None
        </Directory>

        <Directory /home/mariussm/websites/goodworkaround.com>
                Options FollowSymLinks MultiViews
                AllowOverride All
                Order allow,deny
                allow from all
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/goodworkaround.com.error.log

        # Possible values include: debug, info, notice, warn, error, crit,
        # alert, emerg.
        LogLevel warn

        CustomLog ${APACHE_LOG_DIR}/goodworkaround.com.access.log combined

</VirtualHost>

As you can see, it listens on all interfaces (*:80) on port 80, cares only for the hostname goodworkaround.com and has a root folder. So hey, that’s the easy way.