Wednesday, April 18, 2012

ADFS : Problems with SAML and domains

 

Busy testing a 3rd party SAML provider and getting it to integrate with ADFS.

First tried it on my dev. PC using https://mypc/3rdparty.

All well and good – tick that one off – but then I needed to test it from outside of the dev. domain i.e.

https://mypc.mydomain.com/3rdparty.

Firstly, got the error:

“MSIS3020: The relying party trust with identifier 'https://xxx/sp' could not be located.”

OK, so off to the RP properties config. in ADFS.

Click on the “Identifiers” tab.

Click on the existing RP identifier and then click “Remove”. This puts the URL in the “Add” box where you can add the “mydomain.com” piece and then click “Add”

So now you have two identifiers; one without the domain and one with.

Ok – lets try that again.

Get the error:


“The request specified an Assertion Consumer Service URL 'https://xxx/sp…' that is not  configured on the relying party 'https://xxx/sp'.

User Action
Use the AD FS 2.0 Management snap-in to configure an Assertion Consumer Service with the specified URL for this relying party.”

Mr Google leads to this: AD FS 2.0: "The request specified an Assertion Consumer Service URL that is not configured on the relying party"

and states:

“There are two options:
1. Configure the RP so that AssertionConsumerService is not specified in the AuthnRequest
2. Configure the RP to send a AssertionConsumerService value in the AuthnRequest which matches the AssertionConsumerService value on the Endpoints tab of the RP Trust in AD FS 2.0.”

Hmmm – 1 is not an option because it’s a 3rd party product.

Went with 2.

In the RP properties config. in ADFS.

Click on the “Endpoints” tab.

Under “SAML Assertion Consumer Endpoints”:

In my case there were two with bindings for POST and Artifact.

Click on “Edit”, copy the URL, then click on “Add”. Fix the domain, select the binding and an index number that’s not used.

When I finished I had four entries, two POSTS bindings and Artifact bindings.

And then, verily, it all just worked.

Enjoy!

Thursday, April 12, 2012

Tuesday, March 27, 2012

AD : Enumerating UserAccountControl

 

There doesn’t seem to anything built into the .NET framework to do this and it’s a lot easier to read actual names rather than hex boolean manipulation so I rolled my own:

[Flags]
enum UserAccountControl
{
ADS_UF_SCRIPT = 1, // 0x1
ADS_UF_ACCOUNTDISABLE = 2, // 0x2
ADS_UF_HOMEDIR_REQUIRED = 8, // 0x8
ADS_UF_LOCKOUT = 16, // 0x10
ADS_UF_PASSWD_NOTREQD = 32, // 0x20
ADS_UF_PASSWD_CANT_CHANGE = 64, // 0x40
ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 128, // 0x80
ADS_UF_TEMP_DUPLICATE_ACCOUNT = 256, // 0x100
ADS_UF_NORMAL_ACCOUNT = 512, // 0x200
ADS_UF_INTERDOMAIN_TRUST_ACCOUNT = 2048, // 0x800
ADS_UF_WORKSTATION_TRUST_ACCOUNT = 4096, // 0x1000
ADS_UF_SERVER_TRUST_ACCOUNT = 8192, // 0x2000
ADS_UF_DONT_EXPIRE_PASSWD = 65536, // 0x10000
ADS_UF_MNS_LOGON_ACCOUNT = 131072, // 0x20000
ADS_UF_SMARTCARD_REQUIRED = 262144, // 0x40000
ADS_UF_TRUSTED_FOR_DELEGATION = 524288, // 0x80000
ADS_UF_NOT_DELEGATED = 1048576, // 0x100000
ADS_UF_USE_DES_KEY_ONLY = 2097152, // 0x200000
ADS_UF_DONT_REQUIRE_PREAUTH = 4194304, // 0x400000
ADS_UF_PASSWORD_EXPIRED = 8388608, // 0x800000
ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 16777216 // 0x1000000
} 

With this you can write code like:


val = val | (int) UserAccountControl.ADS_UF_DONT_EXPIRE_PASSWD;


Far more readable, I think you’ll agree.


And remember:


To clear a value, use:


val = val & (int) ~UserAccountControl.ADS_UF_ACCOUNTDISABLE;


The ~ is a boolean complement ~ Operator.


Enjoy!

Friday, March 23, 2012

C# : Logging the variables in a class

 

Imagine you have a web site with a bunch of global variables. You want to display them in a debug page. So you could use intellisense and manually traverse through the class but if it’s a big class it’s a right royal pain and you have to keep updating the code as you add new variables.

Enter stage right Reflection.

Type objectType = typeof (GlobalVar);
GlobalVar gv = new GlobalVar();
System.Reflection.FieldInfo[] fieldInfo = objectType.GetFields();

foreach (System.Reflection.FieldInfo info in fieldInfo)
{
xxx.Text = info.Name;

object oText = info.GetValue(null);
if (oText is string)
yyy.Text = (String)oText;
else if (oText is int)
yyy.Text = oText.ToString();
else if (oText is bool)
yyy.Text = oText.ToString();
else if (oText is long)
yyy.Text = oText.ToString();
}


Note the “GetValue(null); “. This is because all the variables in the class are static.



For a non-static class, see C# Tutorial - Using Reflection to Get Object Information.



Enjoy!

Thursday, March 22, 2012

ASP.NET : At least one check box must be checked

 

The ASP.NET Validation Controls are a really neat way of doing user validation. However, they are pretty basic. What about more complicated stuff? For that you need a CustomValidator.

e.g. I have a number of check boxes on the page and one of the validation rules is that at least one of the check boxes must be checked. Mr Google to the rescue and (roll of drums) the answer is:

Put this script at the top of the page:

<script runat="server">

void CustomValidator_CBValidate(Object source, ServerValidateEventArgs args)
{
args.IsValid = (chkBox1.Checked == true) || (chkBox2.Checked == true) || ...;
}

</script>



And then in your page:



<asp:CheckBox ID="chkBox1" Text="xxx" runat="server" />

<asp:CheckBox ID="chkBox2" Text="yyy" runat="server" />

...

<asp:CustomValidator id="CustomValidator1"
runat="server" ErrorMessage="Please select an option"
OnServerValidate="CustomValidator_CBValidate">
</asp:CustomValidator>


Enjoy!



C# : Active Directory Resources

 

Being doing a bit of work in this space and I found the following links to be really useful:

Howto: (Almost) Everything In Active Directory via C#

Everything in Active Directory via C#.NET 3.5

Active Directory and .NET

Active Directory Objects and C#

Active Directory With C#

So if you want to create users, work with their passwords, update their details, add them to groups etc. you’ll find something above to help you.

Enjoy!

Wednesday, March 14, 2012

C# : The server is unwilling to process the request

 

Busy doing some AD work with C#.

I’m creating the user, changing some of the attributes (e.g. setting “DONT_EXPIRE_PASSWORD”) and then setting the password.

Got the exception:

DirectoryServicesCOMException (0x80072035): The server is unwilling to process the request

Mr. Google to the rescue. After sorting through the huge pile of crap, found the answer.

You need to do it in the following order:

  • Create the user
  • Commit changes
  • Set the password
  • Commit changes
  • Change the attributes
  • Commit changes

i.e. Set the password BEFORE doing any attribute CRUD stuff.

Enjoy!

Thursday, March 08, 2012

WCF : Message logging


The best developer tool is Google. 99 % of the time you can find an answer or sample code to your problem.

On the other hand, the worst developer tool is Google. At least half the links are rubbish. There should be some kind of peer review like stackoverflow has to delete crap articles from the Web.

This came about because I was looking for a way to log the actual messages being sent over WCF.

Came across loads of articles, none of which worked 100%. Some were misleading and some were absolute rubbish.

The worst aspect was that they include some small XML snippet which you cut and paste into the web.config without any context i.e. just where are you supposed to insert it?

Anyway, here’s the solution I came up with:

<configuration>
...
  </system.serviceModel>
    <diagnostics>
         <messageLogging 
         logEntireMessage="true" 
         logMalformedMessages="false"
         logMessagesAtServiceLevel="true" 
         logMessagesAtTransportLevel="true"
         maxMessagesToLog="3000"
         maxSizeOfMessageToLog="2000"/>
     </diagnostics>    
  </system.serviceModel>
...
  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel" switchValue=
"Information,ActivityTracing"
        propagateActivity="true">
        <listeners>
          <add name="xml" />
        </listeners>
      </source>
      <source name="System.ServiceModel.MessageLogging">
        <listeners>
          <add name="messages"
                 type="System.Diagnostics.XmlWriterTraceListener"
                 initializeData="c:\...\messages.svclog" />
        </listeners>
      </source>  
    </sources>
       <sharedListeners>
      <add initializeData="C:\...\Trace.svclog"  
type="System.Diagnostics.XmlWriterTraceListener"
        name="xml" />
    </sharedListeners>
    <trace autoflush="true" />
  </system.diagnostics>
...
<configuration>

Enjoy!

Wednesday, February 29, 2012

Visual Studio : "Set As Start Page" doesn't work in the real world

I have a web site that contains a "Default.aspx" but I want the start page to be "abc.aspx".

So in Visual Studio 2010, I right click the "abc.aspx" page and select "Set As Start Page".

Hit F5 - works perfectly.

Deploy it to a real IIS 7 server and WTF - Default.aspx is displayed in all its delights?

Turns out the "Set As Start Page" option only applies to Cassini - the VS internal web server (which is why it works when you hit Run ( = F5)).

In the real world, you have to go to the web site inside the IIS Manager, select "Default Document" and then type abc.aspx and move it up to the top.

There you go!

Enjoy!

msdeploy : Package installation failed - 'managedRuntimeVersion' differs

So there I was trying to use msdeploy to deploy a web site from Visual Studio 2010 into an IIS 7 server on another box using the "Build Deployment Package".

I got the error:

The package installation failed.
Details:
The application pool that you are trying to use has the 'managedRuntimeVersion' property set to 'v4.0'. This application requires 'v2.0'.

My web application used the "Default Web Site" and the application pool that it was connected to (DefaultAppPool) was .NET Framework 2.0. Yeah - I screw around with IIS a lot!

Of course, where I was deploying it to was the more usual .NET Framework 4.0.

Mr. Google to the rescue and the answer is to set the following options under the project / Properties / Package/Publish Web:



You need to tick the two text boxes "Include IIS Settings" and "Include application pool settings".
And away you go with msdeploy.

Enjoy!



Wednesday, February 22, 2012

WIF : Web Platform Installer

WIF has just been added to the Microsoft Web Platform Installer. (WPI)

Just search on the keyword "identity".

Hey - hey - it's becoming mainstream.

Makes it just that bit easier to download.

The WPI is a really useful tool that collects a pile of Microsoft (and other) downloads in one place. Well worth 5 minutes of your time to go and have a look!

Enjopy!