c# - How do I do a SAML login request, without using a third party control? -
i need saml login site. know site using componentpro ultimate saml handle sso on service provider side... functioning identity provider. have sample of how post if purchase control, understanding saml open standard, , specific control shouldn't needed assertion. have sample of how format saml request in straight c#? need specail make work if service provider using 3rd party library componentpro saml library?
clayton, generating , signing saml messages of few classes wrote (below). these classes culmination of our learnings online. assertions specific our system, believe provide great starting point build on. demo purposes, private key certs assumed located in folder under root named "certificates". in production environment, not located under root of website.
------------------------------------------------------------ // default.aspx ------------------------------------------------------------ using system; using system.collections.generic; using system.web; using system.web.ui; using system.web.ui.webcontrols; namespace ssoclient { public partial class _default : system.web.ui.page { protected void page_load(object sender, eventargs e) { ssologin ssologin = new ssologin(); ssologin.saml = ssologin.saml_template; ssologin.serviceproviderurl = ""; ssologin.certificate = new certificate() { path = server.mappath("/certificates") + "/" + "ssoclientcert.pfx", password = "abcd1234" }; ssologin.issuer = "ssoclientcert"; ssologin.nameid = "guest"; ssologin.logout = "http://www.google.com"; ssologin.controller = "home"; ssologin.tokenmethod = "systemid"; ssologin.customtokenforverification = "46"; ssologin.autosubmitmessage = false; ssologin.post(response); ssologin = null; /*ssologout ssologout = new ssologout(); ssologout.saml = ssologout.saml_template; ssologout.serviceproviderurl = ""; ssologout.certificate = new certificate() { path = server.mappath("/certificates") + "/" + "ssoclientcert.pfx", password = "abcd1234" }; ssologout.issuer = "ssoclientcert"; ssologout.nameid = "guest"; ssologout.autosubmitmessage = false; ssologout.post(response); ssologout = null;*/ } } } ------------------------------------------------------------ // classes ------------------------------------------------------------ using system; using system.collections.generic; using system.io; using system.security.cryptography.x509certificates; using system.security.cryptography.xml; using system.text; using system.web; using system.xml; namespace ssoclient { #region certificate class public class certificate { private string _path = ""; private string _password = ""; public string path { { return this._path; } set { this._path = value; } } public string password { { return this._password; } set { this._password = value; } } } #endregion #region ssobase class public abstract class ssobase { public const string hidden_input_template = @"<input type=""hidden"" name=""{0}"" value=""{1}"" />"; private certificate _certificate = null; private string _serviceproviderurl = ""; private string _consumerservicepath = ""; private string _relaystate = ""; private string _messageid = ""; private string _issueinstant = ""; private string _issuer = ""; private string _nameid = ""; private string _sigalg = ""; private string _signature = ""; private string _saml = ""; private string _samlsigned = ""; private bool _autosubmitmessage = false; public certificate certificate { { return this._certificate; } set { this._certificate = value; } } public string serviceproviderurl { { return this._serviceproviderurl; } set { this._serviceproviderurl = value; } } public string consumerservicepath { { return this._consumerservicepath; } set { this._consumerservicepath = value; } } public string relaystate { { return this._relaystate; } set { this._relaystate = value; } } public string messageid { { return this._messageid; } set { this._messageid = value; } } public string issueinstant { { return this._issueinstant; } set { this._issueinstant = value; } } public string issuer { { return this._issuer; } set { this._issuer = value; } } public string nameid { { return this._nameid; } set { this._nameid = value; } } public string sigalg { { return this._sigalg; } set { this._sigalg = value; } } public string signature { { return this._signature; } set { this._signature = value; } } public string saml { { return this._saml; } set { this._saml = value; } } public string samlsigned { { return this._samlsigned; } set { this._samlsigned = value; } } public bool autosubmitmessage { { return this._autosubmitmessage; } set { this._autosubmitmessage = value; } } public ssobase() { this._certificate = null; this._serviceproviderurl = ""; this._consumerservicepath = ""; this._relaystate = system.guid.newguid().tostring(); this._messageid = string.format("_{0}", system.guid.newguid().tostring().replace("-", "").toupper()); this._issueinstant = system.datetime.now.tostring("yyyy-mm-ddthh:mm:ss.fffz"); this._issuer = ""; this._nameid = ""; this._sigalg = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; this._signature = ""; this._saml = ""; this._samlsigned = ""; this._autosubmitmessage = false; } public xmldocument sign(x509certificate2 x509certificate, xmldocument xmldocument, string referenceid) { signedxml signedxml = new signedxml(xmldocument); x509certificate2collection x509certificate2collection; try { x509certificate2collection = new x509certificate2collection(); x509certificate2collection.add(x509certificate); } catch (exception exception) { throw; } keyinfo keyinfo; try { keyinfo = new keyinfo(); keyinfox509data keyinfox509data = new keyinfox509data(); x509certificate2enumerator enumerator = x509certificate2collection.getenumerator(); while (enumerator.movenext()) { keyinfox509data.addcertificate(enumerator.current); } keyinfo.addclause(keyinfox509data); } catch (exception exception) { throw; } xmlelement xmlelement = null; try { signedxml.signingkey = x509certificate.privatekey; signedxml.signedinfo.canonicalizationmethod = "http://www.w3.org/2001/10/xml-exc-c14n#"; reference reference = new reference() { uri = string.concat("#", referenceid) }; reference.addtransform(new xmldsigenvelopedsignaturetransform()); xmldsigexcc14ntransform xmldsigexcc14ntransform = new xmldsigexcc14ntransform(); if (!string.isnullorempty("#default samlp saml ds xs xsi")) { xmldsigexcc14ntransform.inclusivenamespacesprefixlist = "#default samlp saml ds xs xsi"; } reference.addtransform(xmldsigexcc14ntransform); signedxml.addreference(reference); signedxml.keyinfo = keyinfo; signedxml.computesignature(); this._signature = convert.tobase64string(signedxml.signaturevalue, base64formattingoptions.none); xmlelement = signedxml.getxml(); xmlnode root = xmldocument.documentelement; xmlnamespacemanager nsmgr = new xmlnamespacemanager(xmldocument.nametable); nsmgr.addnamespace("saml", "urn:oasis:names:tc:saml:2.0:assertion"); xmlnode issuer = xmldocument.selectsinglenode("//saml:issuer", nsmgr); root.insertafter(xmlelement, issuer); return xmldocument; } catch (exception exception) { return null; } } } #endregion #region ssologin class public class ssologin : ssobase { public const string saml_template = @"<samlp:response id=""@responseid"" version=""2.0"" issueinstant=""@issueinstant"" xmlns:samlp=""urn:oasis:names:tc:saml:2.0:protocol""><saml:issuer xmlns:saml=""urn:oasis:names:tc:saml:2.0:assertion"">@issuer</saml:issuer><samlp:status><samlp:statuscode value=""urn:oasis:names:tc:saml:2.0:status:success"" /></samlp:status><saml:assertion version=""2.0"" id=""@assertionid"" issueinstant=""@issueinstant"" xmlns:saml=""urn:oasis:names:tc:saml:2.0:assertion""><saml:subject><saml:nameid>@nameid</saml:nameid></saml:subject><saml:authnstatement authninstant=""@authninstant"" /><saml:attributestatement><saml:attribute name=""logout"" nameformat=""urn:oasis:names:tc:saml:2.0:attrname-format:basic""><saml:attributevalue>@logout</saml:attributevalue></saml:attribute><saml:attribute name=""controller"" nameformat=""urn:oasis:names:tc:saml:2.0:attrname-format:basic""><saml:attributevalue>@controller</saml:attributevalue></saml:attribute><saml:attribute name=""tokenmethod"" nameformat=""urn:oasis:names:tc:saml:2.0:attrname-format:basic""><saml:attributevalue>@tokenmethod</saml:attributevalue></saml:attribute><saml:attribute name=""customtokenforverification"" nameformat=""urn:oasis:names:tc:saml:2.0:attrname-format:basic""><saml:attributevalue>@customtokenforverification</saml:attributevalue></saml:attribute></saml:attributestatement></saml:assertion></samlp:response>"; private string _assertionid = ""; private string _authninstant = ""; private string _logout = ""; private string _controller = ""; private string _tokenmethod = ""; private string _customtokenforverification = ""; public string assertionid { { return this._assertionid; } set { this._assertionid = value; } } public string authninstant { { return this._authninstant; } set { this._authninstant = value; } } public string logout { { return this._logout; } set { this._logout = value; } } public string controller { { return this._controller; } set { this._controller = value; } } public string tokenmethod { { return this._tokenmethod; } set { this._tokenmethod = value; } } public string customtokenforverification { { return this._customtokenforverification; } set { this._customtokenforverification = value; } } public ssologin() { this._assertionid = string.format("_{0}", system.guid.newguid().tostring().replace("-", "").toupper()); this._authninstant = system.datetime.now.tostring("yyyy-mm-ddthh:mm:ss.fffz"); this._logout = ""; this._controller = ""; this._tokenmethod = ""; this._customtokenforverification = ""; } public void post(httpresponse response) { try { if (base.saml == "") { base.saml = saml_template; } base.saml = base.saml.replace("@responseid", base.messageid); base.saml = base.saml.replace("@issueinstant", base.issueinstant); base.saml = base.saml.replace("@issuer", base.issuer); base.saml = base.saml.replace("@assertionid", this._assertionid); base.saml = base.saml.replace("@authninstant", this._authninstant); base.saml = base.saml.replace("@nameid", base.nameid); base.saml = base.saml.replace("@logout", this._logout); base.saml = base.saml.replace("@controller", this._controller); base.saml = base.saml.replace("@tokenmethod", this._tokenmethod); base.saml = base.saml.replace("@customtokenforverification", this._customtokenforverification); xmldocument xmldocument = new xmldocument(); xmldocument.loadxml(base.saml); xmldocument xmldocumentsigned = this.sign(new x509certificate2(base.certificate.path, base.certificate.password), xmldocument, base.messageid); byte[] signedbytearray = encoding.utf8.getbytes(xmldocumentsigned.innerxml); base.samlsigned = convert.tobase64string(signedbytearray, base64formattingoptions.none); idictionary<string, string> hiddeninputdic = new dictionary<string, string>(); hiddeninputdic.add("samlresponse", base.samlsigned); hiddeninputdic.add("relaystate", base.relaystate); stringbuilder hiddeninputs = new stringbuilder(); foreach (string hiddeninputname in hiddeninputdic.keys) { string hiddenfieldvalue = hiddeninputdic[hiddeninputname]; hiddeninputs.appendformat(ssobase.hidden_input_template + environment.newline, hiddeninputname, httputility.htmlencode(hiddenfieldvalue)); } string samlform = string.format(@" <form id=""samlform"" action=""{0}"" method=""post""> {1} <input type=""submit"" name=""btnlogin"" value=""login"" /> </form>", string.format("{0}{1}", this.serviceproviderurl, base.consumerservicepath), hiddeninputs.tostring()); string pagetemplate = @" <!doctype html> <html xmlns=""http://www.w3.org/1999/xhtml""> <body{0}> <h3>saml sso - login example</h3> <p>please click login button login.</p> <div> {1} </div> <hr> <h3>saml form</h3> <div> <textarea cols=""100"" rows=""50""> {2} </textarea> </div> </body> </html>"; httpcontext httpcontext = httpcontext.current; stringbuilder html = new stringbuilder(); html.appendformat(pagetemplate, base.autosubmitmessage ? @" onload=""document.getelementbyid('samlform').submit();""" : "", samlform, httpcontext.server.htmlencode(samlform)); streamwriter outputstream = new streamwriter(response.outputstream); outputstream.write(html.tostring()); outputstream.flush(); } catch (exception exception) { response.write(exception.tostring()); } } } #endregion #region ssologout class public class ssologout : ssobase { public const string saml_template = @"<saml:logoutrequest id=""@requestid"" version=""2.0"" issueinstant=""@issueinstant"" xmlns:saml=""urn:oasis:names:tc:saml:2.0:protocol""><saml:issuer xmlns:saml=""urn:oasis:names:tc:saml:2.0:assertion"">@issuer</saml:issuer><saml:nameid xmlns:saml=""urn:oasis:names:tc:saml:2.0:assertion"">@nameid</saml:nameid></saml:logoutrequest>"; public ssologout() { } public void post(httpresponse response) { try { if (base.saml == "") { base.saml = saml_template; } base.saml = base.saml.replace("@requestid", base.messageid); base.saml = base.saml.replace("@issueinstant", base.issueinstant); base.saml = base.saml.replace("@issuer", base.issuer); base.saml = base.saml.replace("@nameid", base.nameid); xmldocument xmldocument = new xmldocument(); xmldocument.loadxml(base.saml); xmldocument xmldocumentsigned = this.sign(new x509certificate2(base.certificate.path, base.certificate.password), xmldocument, base.messageid); byte[] signedbytearray = encoding.utf8.getbytes(xmldocumentsigned.innerxml); base.samlsigned = convert.tobase64string(signedbytearray, base64formattingoptions.none); idictionary<string, string> hiddeninputdic = new dictionary<string, string>(); hiddeninputdic.add("samlrequest", base.samlsigned); hiddeninputdic.add("relaystate", base.relaystate); hiddeninputdic.add("sigalg", base.sigalg); hiddeninputdic.add("signature", base.signature); stringbuilder hiddeninputs = new stringbuilder(); foreach (string hiddeninputname in hiddeninputdic.keys) { string hiddenfieldvalue = hiddeninputdic[hiddeninputname]; hiddeninputs.appendformat(ssobase.hidden_input_template + environment.newline, hiddeninputname, httputility.htmlencode(hiddenfieldvalue)); } string samlform = string.format(@" <form id=""samlform"" action=""{0}"" method=""post""> {1} <input type=""submit"" name=""btnlogout"" value=""logout"" /> </form>", string.format("{0}{1}", this.serviceproviderurl, base.consumerservicepath), hiddeninputs.tostring()); string pagetemplate = @" <!doctype html> <html xmlns=""http://www.w3.org/1999/xhtml""> <body{0}> <h3>saml sso - logout example</h3> <p>please click logout button logout.</p> <div> {1} </div> <hr> <h3>saml form</h3> <div> <textarea cols=""100"" rows=""50""> {2} </textarea> </div> </body> </html>"; httpcontext httpcontext = httpcontext.current; stringbuilder html = new stringbuilder(); html.appendformat(pagetemplate, base.autosubmitmessage ? @" onload=""document.getelementbyid('samlform').submit();""" : "", samlform, httpcontext.server.htmlencode(samlform)); streamwriter outputstream = new streamwriter(response.outputstream); outputstream.write(html.tostring()); outputstream.flush(); } catch (exception exception) { response.write(exception.tostring()); } } } #endregion }
Comments
Post a Comment