/// <summary> /// Given a SAML request, this function validates it, and extracts the requested attributes. /// </summary> /// <param name="doc">the xml corresponding to the SAML request</param> /// <returns>the context of the SAML request</returns> public SAMLContext HandleRequest(XmlDocument xmlRequest) { try { int errorCode; SAMLContext context; string issuer = xmlRequest.GetElementsByTagName("Issuer", SAMLConstants.NS_ASSERT).Item(0).InnerText; if ((errorCode = Verify(xmlRequest, issuer)) < 0) { string assertionConsumer = xmlRequest.GetElementsByTagName("AuthnRequest", SAMLConstants.NS_PROTOCOL).Item(0).Attributes["AssertionConsumerServiceURL"].Value; string requestId = xmlRequest.DocumentElement.Attributes["ID"].Value; context = new SAMLContext(errorCode, requestId, assertionConsumer); } else { context = ExtractRequestValues(xmlRequest); } return(context); } catch (Exception ex) { throw new SAMLException("EXCEPTION HandleRequest", ex); } }
/// <summary> /// Generates a SAML response with the given attributes. /// </summary> /// <param name="attrs"></param> /// <returns>the xml corresponding to the SAML response</returns> public XmlDocument GenerateResponse(SAMLContext context) { try { string id = "_" + Guid.NewGuid().ToString(); XmlDocument xmlResponse = GenerateResponseMetadata(context, id); xmlResponse.PreserveWhitespace = true; SignatureUtils.SignDocument(xmlResponse, id, certificate, xmlResponse.GetElementsByTagName("Issuer", SAMLConstants.NS_ASSERT).Item(0)); return(xmlResponse); } catch (Exception ex) { throw new SAMLException("EXCEPTION GenerateResponse", ex); } }
/// <summary> /// /// </summary> /// <param name="context"></param> /// <returns></returns> private XmlDocument GenerateResponseMetadata(SAMLContext context, string id) { DateTime now = DateTime.UtcNow; MemoryStream stream = new MemoryStream(); StreamReader reader; XmlTextReader xmlReader; ResponseType response = new ResponseType(); response.ID = id; response.InResponseTo = context.RequestID; response.Version = SAMLConstants.SAML_VERSION; response.IssueInstant = now; response.Destination = context.AssertionConsumer; response.Consent = SAMLConstants.CONSENT; response.Issuer = new NameIDType(); response.Issuer.Value = thisIssuer; response.Issuer.Format = SAMLConstants.ThisIssuerFormat; response.Status = new StatusType(); response.Status.StatusCode = new StatusCodeType(); response.Status.StatusCode.Value = SAMLConstants.StatusCode.statusCode[context.StatusCode]; if (context.StatusCode != SAMLConstants.StatusCode.SUCCESS) { response.Status.StatusCode.StatusCode = new StatusCodeType(); response.Status.StatusCode.StatusCode.Value = SAMLConstants.StatusCode.statusCode[context.SubStatusCode]; response.Status.StatusMessage = context.StatusMessage; } AssertionType assertion = new AssertionType(); assertion.ID = "_" + Guid.NewGuid().ToString(); assertion.Version = SAMLConstants.SAML_VERSION; assertion.IssueInstant = now; assertion.Issuer = new NameIDType(); assertion.Issuer.Value = thisIssuer; assertion.Issuer.Format = SAMLConstants.ThisIssuerFormat; assertion.Subject = new SubjectType(); NameIDType nameId = new NameIDType(); nameId.Format = "urn:oasis:names:tc:SAML:1.1:nameid- format:unspecified"; //nameId.NameQualifier = "http://C-PEPS.gov.xx"; nameId.Value = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"; SubjectConfirmationType subjectConfirmation = new SubjectConfirmationType(); subjectConfirmation.Method = "urn:oasis:names:tc:SAML:2.0:cm:bearer"; subjectConfirmation.SubjectConfirmationData = new SubjectConfirmationDataType(); subjectConfirmation.SubjectConfirmationData.Address = context.SubjectAddress; subjectConfirmation.SubjectConfirmationData.InResponseTo = context.RequestID; //subjectConfirmation.SubjectConfirmationData.NotBeforeString = "2010-02-03T17:06:18.099Z"; subjectConfirmation.SubjectConfirmationData.NotOnOrAfterString = String.Format("{0:yyyy-MM-ddTHH:mm:ssZ}", now.AddMinutes(validTimeframe)); subjectConfirmation.SubjectConfirmationData.Recipient = context.Issuer; assertion.Subject.Items = new object[] { nameId, subjectConfirmation }; assertion.Conditions = new ConditionsType(); assertion.Conditions.NotBeforeString = String.Format("{0:yyyy-MM-ddTHH:mm:ssZ}", now); assertion.Conditions.NotOnOrAfterString = String.Format("{0:yyyy-MM-ddTHH:mm:ssZ}", now.AddMinutes(validTimeframe)); AudienceRestrictionType audience = new AudienceRestrictionType(); audience.Audience = new string[] { context.Issuer }; // FIXME assertion.Conditions.Items = new ConditionAbstractType[] { audience, new OneTimeUseType() }; AuthnStatementType authnStatement = new AuthnStatementType(); authnStatement.AuthnInstant = now; authnStatement.AuthnContext = new AuthnContextType(); List <AttributeElement> attributes = context.GetAttributes(); object[] attributesDescription = new AttributeType[attributes.Count]; AttributeType attr; XmlAttribute statusAttr; int i = 0; foreach (AttributeElement element in attributes) { attr = new AttributeType(); attr.Name = element.AttrName; attr.NameFormat = element.NameFormat; if (context.StatusCode == SAMLConstants.StatusCode.SUCCESS) { if (element.AttrStatus == SAMLConstants.AttributeStatus.AVAILABLE && element.AttrValue != null) { attr.AttributeValue = new object[] { element.AttrValue } } ; if (element.AttrStatus >= 0) { statusAttr = new XmlDocument(). CreateAttribute(SAMLConstants.ATTRIBUTE_STATUS_STR, SAMLConstants.NS_STORK_ASSER); statusAttr.Value = element.Status; attr.AnyAttr = new XmlAttribute[] { statusAttr }; } } attributesDescription[i++] = attr; } AttributeStatementType attributeStatement = new AttributeStatementType(); attributeStatement.Items = attributesDescription; assertion.Items = new StatementAbstractType[] { authnStatement, attributeStatement }; response.Items = new object[] { assertion }; stream = new MemoryStream(); Serialize(response, stream); reader = new StreamReader(stream); stream.Seek(0, SeekOrigin.Begin); xmlReader = new XmlTextReader(new StringReader(reader.ReadToEnd())); return(Deserialize <XmlDocument>(xmlReader)); }
/// <summary> /// /// </summary> /// <param name="doc"></param> /// <returns>a saml context to be used when generating the response</returns> private SAMLContext ExtractRequestValues(XmlDocument doc) { SAMLContext context = new SAMLContext(SAMLConstants.ErrorCodes.VALID); XmlReader reader = new XmlTextReader(new StringReader(doc.OuterXml)); AuthnRequestType request = Deserialize <AuthnRequestType>(reader); context.AssertionConsumer = request.AssertionConsumerServiceURL; if (IsRepeatedId(request.ID)) { context.ErrorCode = SAMLConstants.ErrorCodes.REPEATED_ID; return(context); } AddId(request.ID); if (thisDestination != null && request.Destination != thisDestination) { context.ErrorCode = SAMLConstants.ErrorCodes.INVALID_DESTINATION; return(context); } if (Math.Abs(request.IssueInstant.Subtract(DateTime.UtcNow).TotalMinutes) > validTimeframe) { context.ErrorCode = SAMLConstants.ErrorCodes.EXPIRED; return(context); } context.Issuer = request.Issuer.Value; context.RequestID = request.ID; XmlElement[] xmlElement = request.Extensions.Any; XmlElement reqAttributes = null; foreach (XmlElement element in xmlElement) { if (element.LocalName == "RequestedAttributes" && element.NamespaceURI == ConfigurationSettingsHelper.GetCriticalConfigSetting(CommonConstants.NS_REQ_ATTRS)) { reqAttributes = element; break; } } if (reqAttributes == null) { context.ErrorCode = SAMLConstants.ErrorCodes.XML_VALIDATION_FAILED; return(context); } try { foreach (XmlElement element in reqAttributes.GetElementsByTagName("RequestedAttribute", ConfigurationSettingsHelper.GetCriticalConfigSetting(CommonConstants.NS_REQ_ATTR))) { XmlAttributeCollection attrCollection = element.Attributes; string name = attrCollection["Name"].Value; // string nameFormat = attrColection["NameFormat"].Value; string isRequired = attrCollection["isRequired"].Value; context.AddAttribute(name, bool.Parse(isRequired)); } } catch (Exception) { //something wrong happend with the attribute processing. //Problably the isRequiredAttribut is not present. Log the event and return an InvalidAttribute response context.ErrorCode = SAMLConstants.ErrorCodes.INVALID_ATTRIBUTES; return(context); } if (context.GetAttributeNames().Count == 0) { context.ErrorCode = SAMLConstants.ErrorCodes.INVALID_ATTRIBUTES; } return(context); }