diff --git a/DotNetCasClient/Security/AssertionRoleProvider.cs b/DotNetCasClient/Security/AssertionRoleProvider.cs index e8978d1..c818ccc 100644 --- a/DotNetCasClient/Security/AssertionRoleProvider.cs +++ b/DotNetCasClient/Security/AssertionRoleProvider.cs @@ -1,163 +1,224 @@ -/* - * Licensed to Apereo under one or more contributor license - * agreements. See the NOTICE file distributed with this work - * for additional information regarding copyright ownership. - * Apereo licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a - * copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#pragma warning disable 1591 - -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Configuration.Provider; -using System.Text; -using System.Security.Principal; -using System.Web; -using System.Web.Security; - -namespace DotNetCasClient.Security -{ - public class AssertionRoleProvider : RoleProvider - { - public const string ROLE_ATTRIBUTE_NAME = "roleAttributeName"; - - private readonly static IList EMPTY_LIST = new List(0).AsReadOnly(); - - private string roleAttribute; - - public override string ApplicationName - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - - public override void AddUsersToRoles(string[] usernames, string[] roleNames) - { - throw new NotImplementedException(); - } - - public override void Initialize(string name, NameValueCollection config) - { - if (config == null) - { - throw new ArgumentNullException("config"); - } - - // Assign the provider a default name if it doesn't have one - if (String.IsNullOrEmpty(name)) - { - name = "CasAssertionRoleProvider"; - } - base.Initialize(name, config); - - roleAttribute = config[ROLE_ATTRIBUTE_NAME]; - if (roleAttribute == null) - { - throw new ProviderException(ROLE_ATTRIBUTE_NAME + " is required but has not been provided."); - } - if (roleAttribute == string.Empty) - { - throw new ProviderException(ROLE_ATTRIBUTE_NAME + " roleAttribute must be non-empty string."); - } - } - - public override void CreateRole(string roleName) - { - throw new NotImplementedException(); - } - - public override bool DeleteRole(string roleName, bool throwOnPopulatedRole) - { - throw new NotImplementedException(); - } - - public override string[] FindUsersInRole(string roleName, string usernameToMatch) - { - throw new NotImplementedException(); - } - - /// - /// Get all the roles we know about from the current user's CAS assertion. - /// This operation is synonymous with . - /// - /// List of all roles belonging to current user. - public override string[] GetAllRoles() - { - IList roles = GetCurrentUserRoles(); - if (roles is Array) - { - return (string[])roles; - } - string[] roleArray = new string[roles.Count]; - for (int i = 0; i < roles.Count; i++) - { - roleArray[i] = roles[i]; - } - return roleArray; - } - - public override string[] GetRolesForUser(string username) - { - if (CasAuthentication.CurrentPrincipal.Identity.Name != username) - { - throw new ProviderException("Cannot fetch roles for user other than that of current context."); - } - return GetAllRoles(); - } - - public override string[] GetUsersInRole(string roleName) - { - throw new NotImplementedException(); - } - - public override bool IsUserInRole(string username, string roleName) - { - if (CasAuthentication.CurrentPrincipal.Identity.Name != username) - { - throw new ProviderException("Cannot fetch roles for user other than that of current context."); - } - return GetCurrentUserRoles().Count > 0; - } - - public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames) - { - throw new NotImplementedException(); - } - - public override bool RoleExists(string roleName) - { - throw new NotImplementedException(); - } - - private IList GetCurrentUserRoles() - { - ICasPrincipal principal = CasAuthentication.CurrentPrincipal; - if (principal == null) - { - return EMPTY_LIST; - } - IList roles = principal.Assertion.Attributes[roleAttribute]; - if (roles == null) - { - roles = EMPTY_LIST; - } - return roles; - } - - } -} - -#pragma warning restore 1591 \ No newline at end of file +/* + * Licensed to Apereo under one or more contributor license + * agreements. See the NOTICE file distributed with this work + * for additional information regarding copyright ownership. + * Apereo licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a + * copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#pragma warning disable 1591 + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Configuration.Provider; +using System.Text; +using System.Security.Principal; +using System.Web; +using System.Web.Security; + +namespace DotNetCasClient.Security +{ + public class AssertionRoleProvider : RoleProvider + { + public const string ROLE_ATTRIBUTE_NAME = "roleAttributeName"; + + private readonly static IList EMPTY_LIST = new List(0).AsReadOnly(); + + private string roleAttribute; + + public override string ApplicationName + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public override void AddUsersToRoles(string[] usernames, string[] roleNames) + { + throw new NotImplementedException(); + } + + public override void Initialize(string name, NameValueCollection config) + { + if (config == null) + { + throw new ArgumentNullException("config"); + } + + // Assign the provider a default name if it doesn't have one + if (String.IsNullOrEmpty(name)) + { + name = "CasAssertionRoleProvider"; + } + base.Initialize(name, config); + + roleAttribute = config[ROLE_ATTRIBUTE_NAME]; + if (roleAttribute == null) + { + throw new ProviderException(ROLE_ATTRIBUTE_NAME + " is required but has not been provided."); + } + if (roleAttribute == string.Empty) + { + throw new ProviderException(ROLE_ATTRIBUTE_NAME + " roleAttribute must be non-empty string."); + } + } + + public override void CreateRole(string roleName) + { + throw new NotImplementedException(); + } + + public override bool DeleteRole(string roleName, bool throwOnPopulatedRole) + { + throw new NotImplementedException(); + } + + public override string[] FindUsersInRole(string roleName, string usernameToMatch) + { + throw new NotImplementedException(); + } + + /// + /// Gets a list of all the roles for the configured applicationName. + /// + /// A string array containing the names of all the roles stored in the data + /// source for the configured applicationName. + /// This method will always throw a as the + /// CAS client is not able to retrieve a list of all roles from the CAS server. + public override string[] GetAllRoles() + { + throw new NotImplementedException(); + } + + /// + /// Gets a list of role names of which the specified user is a member. + /// + /// The user to get roles for + /// A string array containing the names of all the roles + public override string[] GetRolesForUser(string username) + { + if (CasAuthentication.CurrentPrincipal.Identity.Name != username) + { + // Role membership is provided by the CAS server, not this client, so it is + // impossible to determine the role membership for other identities + throw new ProviderException("Cannot fetch roles for user other than that of current context."); + } + + // Call the private method to get all roles for the specified (current) user + IList roles = GetCurrentUserRoles(); + + if (roles is Array) + { + // The roles list can be directly cast to a string array and returned to the caller + return (string[])roles; + } + + // The elements of the roles list must be manually copied into a new string array + // that can be returned to the caller + string[] roleArray = new string[roles.Count]; + for (int i = 0; i < roles.Count; i++) + { + roleArray[i] = roles[i]; + } + return roleArray; + } + + public override string[] GetUsersInRole(string roleName) + { + throw new NotImplementedException(); + } + + /// + /// Determines whether or not the specified user is a member of the specified role. + /// + /// The identity of the current user + /// The role to check for membership + /// A Boolean indicating whether or not the user is a member of the role + public override bool IsUserInRole(string username, string roleName) + { + if (CasAuthentication.CurrentPrincipal.Identity.Name != username) + { + // Role membership is provided by the CAS server, not this client, so it is + // impossible to determine the role membership for other identities + throw new ProviderException("Cannot fetch roles for user other than that of current context."); + } + + // Get the list of roles the current user has + IList roles = GetCurrentUserRoles(); + + // Determine if any of the current user roles match the specified role name + foreach (string role in roles) + { + if (string.Compare(role, roleName, true) == 0) + { + // Role names match, so the current user is in the specified role + return true; + } + } + + // Current user is not in any roles that match the specified role + return false; + } + + public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames) + { + throw new NotImplementedException(); + } + + public override bool RoleExists(string roleName) + { + throw new NotImplementedException(); + } + + /// + /// Gets all the roles of which the current user is a member. + /// + /// A list of role names + private IList GetCurrentUserRoles() + { + // Attempt to get the identity of the current user + ICasPrincipal principal = CasAuthentication.CurrentPrincipal; + if (principal == null) + { + // No identity is set in the current CAS context, so there cannot be any role + // membership + return EMPTY_LIST; + } + + // Assert the configured role attribute name exists in the list of CAS assertion + // attributes + if (principal.Assertion.Attributes.ContainsKey(roleAttribute)) + { + // Obtain the attribute in the CAS assertion that contains the list of role for the + // current user + IList roles = principal.Assertion.Attributes[roleAttribute]; + if (roles == null) + { + // The current user is not a member of any roles + return EMPTY_LIST; + } + + return roles; + } + else + { + // The CAS assertion does not contain the attribute configured for role membership, + // so assume the user is not a member of any roles + return EMPTY_LIST; + } + } + } +} + +#pragma warning restore 1591 diff --git a/DotNetCasClient/Validation/CasSaml11Response.cs b/DotNetCasClient/Validation/CasSaml11Response.cs index 5cff83e..a49b216 100644 --- a/DotNetCasClient/Validation/CasSaml11Response.cs +++ b/DotNetCasClient/Validation/CasSaml11Response.cs @@ -6,9 +6,9 @@ * Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a * copy of the License at: - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -36,7 +36,7 @@ class CasSaml11Response // The SAML 1.1 Assertion namespace const string SAML11_ASSERTION_NAMESPACE = "urn:oasis:names:tc:SAML:1.0:assertion"; - private static readonly Logger protoLogger = new Logger(Category.Protocol); + private static readonly Logger protoLogger = new Logger(Category.Protocol); // Tolerance ticks for checking the current time against the SAML // Assertion valid times. @@ -99,7 +99,7 @@ private void ProcessValidAssertion() protoLogger.Debug("Unmarshalling SAML response"); XmlDocument document = new XmlDocument(); document.Load(new StringReader(_CasResponse)); - + XmlNamespaceManager nsmgr = new XmlNamespaceManager(document.NameTable); nsmgr.AddNamespace("assertion", SAML11_ASSERTION_NAMESPACE); @@ -112,12 +112,6 @@ private void ProcessValidAssertion() throw new TicketValidationException("No assertions found."); } - XmlReaderSettings xmlReaderSettings = new XmlReaderSettings(); - xmlReaderSettings.ConformanceLevel = ConformanceLevel.Auto; - xmlReaderSettings.IgnoreWhitespace = true; - xmlReaderSettings.IgnoreComments = true; - xmlReaderSettings.CloseInput = true; - foreach (XmlNode assertionNode in assertions) { XmlNode conditionsNode = assertionNode.SelectSingleNode("descendant::assertion:Conditions", nsmgr); @@ -148,23 +142,16 @@ private void ProcessValidAssertion() protoLogger.Debug("No AuthenticationStatement found in SAML response."); throw new TicketValidationException("No AuthenticationStatement found in the CAS response."); } - - string authMethod = SamlUtils.GetAttributeValue(authenticationStmtNode.Attributes, "AuthenticationMethod"); - + XmlNode nameIdentifierNode = assertionNode.SelectSingleNode("child::assertion:AuthenticationStatement/child::assertion:Subject/child::assertion:NameIdentifier", nsmgr); if (nameIdentifierNode == null) { protoLogger.Debug("No NameIdentifier found in SAML response."); throw new TicketValidationException("No NameIdentifier found in AuthenticationStatement of the CAS response."); } - + string subject = nameIdentifierNode.FirstChild.Value; - IList authValues = new List(); - IDictionary> authenticationAttributes = new Dictionary>(); - authValues.Add(authMethod); - authenticationAttributes.Add("samlAuthenticationStatement::authMethod", authValues); - IAssertion casAssertion; XmlNode attributeStmtNode = assertionNode.SelectSingleNode("descendant::assertion:AttributeStatement", nsmgr); @@ -177,9 +164,9 @@ private void ProcessValidAssertion() { casAssertion = new Assertion(subject, notBefore, notOnOrAfter); } - + CasPrincipal = new CasPrincipal(casAssertion, null, null); - + return; } }