Skip to content
This repository has been archived by the owner on Jun 23, 2021. It is now read-only.

Commit

Permalink
Revert "Revert "Init. upload""
Browse files Browse the repository at this point in the history
This reverts commit 937bbd3.
  • Loading branch information
sbidy committed Mar 13, 2017
1 parent 937bbd3 commit c807ce6
Show file tree
Hide file tree
Showing 13 changed files with 948 additions and 31 deletions.
Binary file added Microsoft.IdentityServer.Web.dll
Binary file not shown.
171 changes: 171 additions & 0 deletions privacyIDEAADFSProvider/Adapter.cs
@@ -0,0 +1,171 @@
using System.Net;
using Microsoft.IdentityServer.Web.Authentication.External;
using Claim = System.Security.Claims.Claim;
using System.IO;
using System.Text;
using System.Xml;
using System.Diagnostics;

// b6483f285cb7b6eb
namespace privacyIDEAADFSProvider
{
public class Adapter : IAuthenticationAdapter
{
private string privacyIDEAurl;
private string privacyIDEArealm;
private string username;
private bool ssl = true;
private string erromessage;
private string wellcomemessage;
private string token;
private string admin_user;
private string admin_pw;

public IAuthenticationAdapterMetadata Metadata
{
//get { return new <instance of IAuthenticationAdapterMetadata derived class>; }
get { return new AdapterMetadata(); }
}
/// <summary>
/// Initiates a new authentication process and returns to the ADFS system.
/// </summary>
/// <param name="identityClaim">Claim information from the ADFS</param>
/// <param name="request">The http request</param>
/// <param name="authContext">The context for the authentication</param>
/// <returns>new instance of IAdapterPresentationForm</returns>
public IAdapterPresentation BeginAuthentication(Claim identityClaim, HttpListenerRequest request, IAuthenticationContext authContext)
{
// seperates the username from the domain
// TODO: Map the domain to the PI3A realm
string[] tmp = identityClaim.Value.Split('\\');
if(tmp.Length > 1) username = tmp[1];
else username = tmp[0];
// check if ssl is disabled in the config
// TODO: Delete for security reasons
if (!ssl) ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;

// trigger challenge
OTPprovider otp_prov = new OTPprovider(privacyIDEAurl);
// get a new admin token for all requests
token = otp_prov.getAuthToken(admin_user, admin_pw);
// trigger a challenge (SMS, Mail ...) for the the user
otp_prov.triggerChellenge(username,privacyIDEArealm,token);

return new AdapterPresentationForm(wellcomemessage);
}

// TODO remove ?
public bool IsAvailableForUser(Claim identityClaim, IAuthenticationContext authContext)
{
return true; //its all available for now
}

public void OnAuthenticationPipelineLoad(IAuthenticationMethodConfigData configData)
{
//this is where AD FS passes us the config data, if such data was supplied at registration of the adapter
if (configData != null)
{
if (configData.Data != null)
{
// load the config file
// TODO: Handle errors and exceptions
using (StreamReader reader = new StreamReader(configData.Data, Encoding.UTF8))
{
string config = reader.ReadToEnd();
XmlDocument doc = new XmlDocument();
doc.LoadXml(config);
// parse the xml document
// TODO: check for the correctness ??
XmlNode node = doc.DocumentElement.SelectSingleNode("/server/url");
privacyIDEAurl = node.InnerText;
node = doc.DocumentElement.SelectSingleNode("/server/realm");
privacyIDEArealm = node.InnerText;
node = doc.DocumentElement.SelectSingleNode("/server/ssl");
// SSL check activate or disabel
// TODO: Should be removed !?
ssl = node.InnerText.ToLower() == "false" ? false : true;
// Text in html document
node = doc.DocumentElement.SelectSingleNode("/server/interface/wellcomemessage");
wellcomemessage = node.InnerText;
node = doc.DocumentElement.SelectSingleNode("/server/interface/errormessage");
erromessage = node.InnerText;
// admin credentials
node = doc.DocumentElement.SelectSingleNode("/server/adminuser");
admin_user = node.InnerText;
node = doc.DocumentElement.SelectSingleNode("/server/adminpw");
admin_pw = node.InnerText;
#if DEBUG
Debug.WriteLine("Server:" + privacyIDEAurl + " Realm:" + privacyIDEArealm + " SSL status: " + ssl);
#endif
}
}
}
}
/// <summary>
/// cleanup function - nothing to do her
/// </summary>
public void OnAuthenticationPipelineUnload()
{
}
/// <summary>
/// Called on error and represents the authform with a error message
/// </summary>
/// <param name="request">the http request object</param>
/// <param name="ex">exception message</param>
/// <returns>new instance of IAdapterPresentationForm derived class</returns>
public IAdapterPresentation OnError(HttpListenerRequest request, ExternalAuthenticationException ex)
{
return new AdapterPresentationForm(true, erromessage);
}
/// <summary>
/// Function call after the user hits submit - it proofs the values (OTP pin)
/// </summary>
/// <param name="authContext"></param>
/// <param name="proofData"></param>
/// <param name="request"></param>
/// <param name="outgoingClaims"></param>
/// <returns></returns>
public IAdapterPresentation TryEndAuthentication(IAuthenticationContext authContext, IProofData proofData, HttpListenerRequest request, out Claim[] outgoingClaims)
{
outgoingClaims = new Claim[0];
if (ValidateProofData(proofData, authContext))
{
//authn complete - return authn method
outgoingClaims = new[]
{
// Return the required authentication method claim, indicating the particulate authentication method used.
new Claim( "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod", "http://schemas.microsoft.com/ws/2012/12/authmethod/otp")
};
return null;
}
else
{
//authentication not complete - return new instance of IAdapterPresentationForm derived class
return new AdapterPresentationForm(true, erromessage);
}
}

bool ValidateProofData(IProofData proofData, IAuthenticationContext authContext)
{
if (proofData == null || proofData.Properties == null || !proofData.Properties.ContainsKey("otpvalue"))
throw new ExternalAuthenticationException("Error - no answer found", authContext);

if (!ssl)
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;

try
{
string otpvalue = (string)proofData.Properties["otpvalue"];
OTPprovider otp_prov = new OTPprovider(privacyIDEAurl);
#if DEBUG
Debug.WriteLine("OTP Code: " + otpvalue + " User: " + username + " Server:" + privacyIDEAurl);
#endif
return otp_prov.getAuthOTP(username, otpvalue, privacyIDEArealm);
}
catch
{
throw new ExternalAuthenticationException("Error - cant validate the otp value", authContext);
}
}
}
}
80 changes: 80 additions & 0 deletions privacyIDEAADFSProvider/AdapterMetadata.cs
@@ -0,0 +1,80 @@
using System.Collections.Generic;
using System.Globalization;
using Microsoft.IdentityServer.Web.Authentication.External;

namespace privacyIDEAADFSProvider
{
class AdapterMetadata : IAuthenticationAdapterMetadata
{
//Returns the name of the provider that will be shown in the AD FS management UI (not visible to end users)
public string AdminName
{
get { return "privacyIDEA_ADFS_provider"; }
}

//Returns an array of strings containing URIs indicating the set of authentication methods implemented by the adapter
/// AD FS requires that, if authentication is successful, the method actually employed will be returned by the
/// final call to TryEndAuthentication(). If no authentication method is returned, or the method returned is not
/// one of the methods listed in this property, the authentication attempt will fail.
public virtual string[] AuthenticationMethods
{
get { return new[] { "http://schemas.microsoft.com/ws/2012/12/authmethod/otp" }; }
}

/// Returns an array indicating which languages are supported by the provider. AD FS uses this information
/// to determine the best language\locale to display to the user.
public int[] AvailableLcids
{
get
{
return new[] { new CultureInfo("en-us").LCID, new CultureInfo("de-de").LCID };
}
}

/// Returns a Dictionary containing the set of localized friendly names of the provider, indexed by lcid.
/// These Friendly Names are displayed in the "choice page" offered to the user when there is more than
/// one secondary authentication provider available.
public Dictionary<int, string> FriendlyNames
{
get
{
Dictionary<int, string> _friendlyNames = new Dictionary<int, string>();
_friendlyNames.Add(new CultureInfo("en-us").LCID, "privacyIDEA ADFS authentication provider");
_friendlyNames.Add(new CultureInfo("de-de").LCID, "privacyIDEA ADFS Authentikationsprovider");
return _friendlyNames;
}
}

/// Returns a Dictionary containing the set of localized descriptions (hover over help) of the provider, indexed by lcid.
/// These descriptions are displayed in the "choice page" offered to the user when there is more than one
/// secondary authentication provider available.
public Dictionary<int, string> Descriptions
{
get
{
Dictionary<int, string> _descriptions = new Dictionary<int, string>();
_descriptions.Add(new CultureInfo("en-us").LCID, "privacyIDEA ADFS provider to access the api");
_descriptions.Add(new CultureInfo("de-de").LCID, "privacyIDEA ADFS Provider zur Bedienung der API.");
return _descriptions;
}
}

/// Returns an array indicating the type of claim that that the adapter uses to identify the user being authenticated.
/// Note that although the property is an array, only the first element is currently used.
/// MUST BE ONE OF THE FOLLOWING
/// "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"
/// "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"
/// "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
/// "http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid"
public string[] IdentityClaims
{
get { return new[] { "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname" }; }
}

//All external providers must return a value of "true" for this property.
public bool RequiresIdentity
{
get { return true; }
}
}
}
53 changes: 53 additions & 0 deletions privacyIDEAADFSProvider/AdapterPresentationForm.cs
@@ -0,0 +1,53 @@
using Microsoft.IdentityServer.Web.Authentication.External;

namespace privacyIDEAADFSProvider
{
class AdapterPresentationForm : IAdapterPresentationForm
{
public string errormessage = "";
public string wellcomemassage = "";
private bool error = false;

public AdapterPresentationForm(bool error, string errormessage)
{
this.error = error;
this.errormessage = errormessage;
}
public AdapterPresentationForm(string wellcomemassage)
{
this.wellcomemassage = wellcomemassage;
}

/// Returns the HTML Form fragment that contains the adapter user interface. This data will be included in the web page that is presented
/// to the cient.
public string GetFormHtml(int lcid)
{
string htmlTemplate = Resources.AuthPage; // return normal page
if (error)
{
htmlTemplate = htmlTemplate.Replace("#ERROR#", errormessage);
htmlTemplate = htmlTemplate.Replace("#MESSAGE#", wellcomemassage);
}
else
{
htmlTemplate = htmlTemplate.Replace("#MESSAGE#", wellcomemassage);
htmlTemplate = htmlTemplate.Replace("#ERROR#", "");
}
return htmlTemplate;
}

/// Return any external resources, ie references to libraries etc., that should be included in
/// the HEAD section of the presentation form html.
public string GetFormPreRenderHtml(int lcid)
{
return null;
}

//returns the title string for the web page which presents the HTML form content to the end user
public string GetPageTitle(int lcid)
{
return "privacyIDEA OTP Adapter";
}

}
}
23 changes: 23 additions & 0 deletions privacyIDEAADFSProvider/AuthError.html
@@ -0,0 +1,23 @@
<div id="loginArea">
<form method="post" id="loginForm">
<!-- These inputs are required by the presentation framework. Do not modify or remove -->
<input id="authMethod" type="hidden" name="AuthMethod" value="%AuthMethod%" />
<input id="context" type="hidden" name="Context" value="%Context%" />
<!-- End inputs are required by the presentation framework. -->
<p id="pageIntroductionText" style="color:red"> Wrong One-Time-Password. Please try again!</p>
<label for="otpvalue" class="block">One-Time-Password</label>
<input id="otpvalue" name="otpvalue" type="text" value="" class="text" placeholder="OTP Password" size="30" />
<div id="submissionArea" class="submitMargin">
<input id="submitButton" type="submit" name="Submit" value="Submit" />
</div>
</form>
<div id="intro" class="groupMargin">

</div>
<!--<script type="text/javascript" language="JavaScript">
//<![CDATA[
function AuthPage() { }
AuthPage.submitAnswer = function () { return true; };
//]]>
</script>-->
</div>
23 changes: 23 additions & 0 deletions privacyIDEAADFSProvider/AuthPage.html
@@ -0,0 +1,23 @@
<div id="loginArea">
<form method="post" id="loginForm">
<!-- These inputs are required by the presentation framework. Do not modify or remove -->
<input id="authMethod" type="hidden" name="AuthMethod" value="%AuthMethod%" />
<input id="context" type="hidden" name="Context" value="%Context%" />
<!-- End inputs are required by the presentation framework. -->
<p id="pageIntroductionText" style="color:red">#ERROR#</p>
<label for="otpvalue" class="block">#MESSAGE#</label>
<input id="otpvalue" name="otpvalue" type="text" value="" class="text" placeholder="OTP Password" size="30"/>
<div id="submissionArea" class="submitMargin">
<input id="submitButton" type="submit" name="Submit" value="Submit"/>
</div>
</form>
<div id="intro" class="groupMargin">

</div>
<!--<script type="text/javascript" language="JavaScript">
//<![CDATA[
function AuthPage() { }
AuthPage.submitAnswer = function () { return true; };
//]]>
</script>-->
</div>
12 changes: 0 additions & 12 deletions privacyIDEAADFSProvider/Class1.cs

This file was deleted.

19 changes: 19 additions & 0 deletions privacyIDEAADFSProvider/Install/Install-ADFSProvider.ps1
@@ -0,0 +1,19 @@
# Install the provider

Set-location "C:\Windows\System32\privacyIDEAprovider"
[System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
$publish = New-Object System.EnterpriseServices.Internal.Publish
$publish.GacInstall("C:\Windows\System32\privacyIDEAprovider\privacyIDEAADFSProvider.dll")

$typeName = "privacyIDEAADFSProvider.Adapter, privacyIDEAADFSProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b6483f285cb7b6eb"
Register-AdfsAuthenticationProvider -TypeName $typeName -Name "privacyIDEAADFSProvider" -ConfigurationFilePath "C:\Windows\System32\privacyIDEAprovider\config.xml" -Verbose

# Remove the provider

Unregister-AdfsAuthenticationProvider -Name "privacyIDEAADFSProvider"
Set-location "C:\Windows\System32\privacyIDEAprovider"
[System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
$publish = New-Object System.EnterpriseServices.Internal.Publish
$publish.GacRemove("C:\Windows\System32\privacyIDEAprovider\privacyIDEAADFSProvider.dll")

Restart-Service adfssrv

0 comments on commit c807ce6

Please sign in to comment.