public void RequiresAuthenticationAttribute_Authorize_Allowed_Authenticated_User() { RequiresAuthenticationAttribute attr = new RequiresAuthenticationAttribute(); using (AuthorizationContext context = new AuthorizationContext(/*instance*/ null, "testOp", "testOpType", /*IServiceProvider*/ null, /*items*/ null)) { AuthorizationResult result = attr.Authorize(this.CreateIPrincipal("name"), context); Assert.AreSame(result, AuthorizationResult.Allowed, "Expected authorization to be allowed on new principal"); } }
/// <summary> /// Determines whether the given <paramref name="principal"/> is authorized to perform a specific operation /// described by the given <paramref name="authorizationContext"/>. /// </summary> /// <remarks>This method is the concrete entry point for authorization. It delegates to the derived class's /// <see cref="IsAuthorized"/> method for implementation-specific authorization. /// </remarks> /// <param name="principal">The <see cref="IPrincipal"/> to be authorized.</param> /// <param name="authorizationContext">The <see cref="AuthorizationContext"/> describing the context in which /// authorization has been requested.</param> /// <returns>An <see cref="AuthorizationResult"/> that indicates whether the operation is allowed or denied. /// A return of <see cref="AuthorizationResult.Allowed"/> indicates the operation is allowed. /// A return of any other (non-null) <see cref="AuthorizationResult"/> indicates the request has been denied. /// The user visible error message for the denial is found in <see cref="AuthorizationResult.ErrorMessage"/>. /// </returns> public AuthorizationResult Authorize(IPrincipal principal, AuthorizationContext authorizationContext) { if (principal == null) { throw new ArgumentNullException("principal"); } if (authorizationContext == null) { throw new ArgumentNullException("authorizationContext"); } return this.IsAuthorized(principal, authorizationContext); }
public void RequiresAuthenticationAttribute_Authorize_Denied_Anonymous_User() { RequiresAuthenticationAttribute attr = new RequiresAuthenticationAttribute(); using (AuthorizationContext context = new AuthorizationContext(/*instance*/ null, "testOp", "testOpType", /*IServiceProvider*/ null, /*items*/ null)) { AuthorizationResult result = attr.Authorize(new GenericPrincipal(WindowsIdentity.GetAnonymous(), null), context); Assert.AreNotSame(result, AuthorizationResult.Allowed, "Expected denied result for anon user"); string expectedMessage = String.Format(CultureInfo.CurrentCulture, Resource.AuthorizationAttribute_Default_Message, context.Operation); Assert.AreEqual(expectedMessage, result.ErrorMessage, "Expected to see default denial error message"); } }
public void AuthorizationContext_Ctor_Template_With_ServiceProvider() { IServiceProvider provider = new AuthorizationContextServiceProvider(); using (AuthorizationContext context = new AuthorizationContext(provider)) { // GetService should delegate to supplied provider string mockStringService = context.GetService(typeof(string)) as string; Assert.AreEqual("mockStringService", mockStringService, "Expected GetService to delegate to mock provider"); // Shared validation logic for templates and container this.Validate_AuthorizationContext_Template(context); this.Validate_AuthorizationContext_ServiceContainer(context); } }
public void AuthorizationContext_Ctor_Template_No_ServiceProvider() { // Null is allowed for IServiceProvider using (AuthorizationContext context = new AuthorizationContext(null)) { // Random GetService request does not throw and returns null object service = context.GetService(typeof(string)); Assert.IsNull(service, "Expected GetService to return null"); // Shared validation logic for templates and container this.Validate_AuthorizationContext_Template(context); this.Validate_AuthorizationContext_ServiceContainer(context); } }
public void RequiresRoleAttribute_NoRolesDefined_Throws() { // Validate that we can access all forms of the Roles property without an exception var ignored = new RequiresRoleAttribute().Roles; ignored = new RequiresRoleAttribute((string)null).Roles; ignored = new RequiresRoleAttribute((string[])null).Roles; // But attempting do authorization with null roles throws using (AuthorizationContext context = new AuthorizationContext(/*instance*/ null, "testOp", "testOpType", /*IServiceProvider*/ null, /*items*/ null)) { ExceptionHelper.ExpectInvalidOperationException( () => { new RequiresRoleAttribute((string[])null).Authorize(this.CreateIPrincipal("John Doe"), context); }, Resource.RequiresRoleAttribute_MustSpecifyRole); } }
public void AuthorizationContext_Ctor_And_Properties() { // Operation param cannot be null or empty ExceptionHelper.ExpectArgumentNullExceptionStandard(() => new AuthorizationContext(/*instance*/ null, /*operation*/ null, "operationType", /*serviceProvider*/ null, items: null), "operation"); ExceptionHelper.ExpectArgumentNullExceptionStandard(() => new AuthorizationContext(/*instance*/ null, /*operation*/ string.Empty, "operationType", /*serviceProvider*/ null, items: null), "operation"); // Operation param cannot be null or empty ExceptionHelper.ExpectArgumentNullExceptionStandard(() => new AuthorizationContext(/*instance*/ null, "operation", /*operationType*/ null, /*serviceProvider*/ null, items: null), "operationType"); ExceptionHelper.ExpectArgumentNullExceptionStandard(() => new AuthorizationContext(/*instance*/ null, "operation", /*operationType*/ string.Empty, /*serviceProvider*/ null, items: null), "operationType"); string instance = "mockEntity"; // type is only required to be object string operation = "testOp"; string operationType = "Query"; IServiceProvider serviceProvider = new AuthorizationContextServiceProvider(); Dictionary<object, object> items = new Dictionary<object, object>(); items["mockItem"] = "mockValue"; // Fully formed valid ctor using (AuthorizationContext context = new AuthorizationContext(instance, operation, operationType, serviceProvider, items)) { // Instance and Operation should be what the ctor set Assert.AreEqual(instance, context.Instance, "AuthorizationContext.Instance property failure"); Assert.AreEqual(operation, context.Operation, "AuthorizationContext.Operation property failure"); Assert.AreEqual(operationType, context.OperationType, "AuthorizationContext.Operation property failure"); // The service provider gets wrapped, so verify we can ask for a service it knew how to provide string mockStringService = (string)context.GetService(typeof(string)); Assert.AreEqual("mockStringService", mockStringService, "AuthorizationContext.GetService() failed to respect input service provider"); // The items param should have been cloned, so verify it has the same content Assert.IsNotNull(context.Items, "AuthorizationContext.Items property failure"); Assert.IsTrue(context.Items.ContainsKey("mockItem"), "AuthorizationContext.Items failed to clone input items"); Assert.AreEqual("mockValue", context.Items["mockItem"], "AuthorizationContext.Items failed to set initial value correctly"); // Add item to original. The snapshot in the context should be unaffected. items["mockItem2"] = "mockValue2"; Assert.IsFalse(context.Items.ContainsKey("mockItem2"), "AuthorizationContext items should have copied snapshot input Items"); // Add an item to the context's Items to verify it is mutable context.Items["mockItem3"] = "mockValue3"; Assert.IsTrue(context.Items.ContainsKey("mockItem3") && (string)context.Items["mockItem3"] == "mockValue3", "Could not modify AuthorizationContext.Items"); // Share logic to validate ServiceContainer this.Validate_AuthorizationContext_ServiceContainer(context); } }
protected override AuthorizationResult IsAuthorized(IPrincipal principal, AuthorizationContext authorizationContext) { // Allowed only on domain operations for entities with a StateName property PropertyInfo property = authorizationContext.Instance == null ? null : authorizationContext.Instance.GetType().GetProperty("StateName"); string stateName = property == null ? null : property.GetValue(authorizationContext.Instance, null) as string; if (stateName == null) { throw new InvalidOperationException("The RequiresUserForStateAttribute can be used only on entities with a StateName property"); } // If not the city, it is allowed if (!string.Equals(this._stateName, stateName, StringComparison.OrdinalIgnoreCase)) { return AuthorizationResult.Allowed; } // It is the city. Let base class continue the authorization return base.IsAuthorized(principal, authorizationContext); }
public void RequiresRoleAttribute_Authorize_SingleAttribute() { IPrincipal user1 = this.CreateIPrincipal("user1", "role1"); IPrincipal user2 = this.CreateIPrincipal("user1", "role2"); RequiresRoleAttribute requireRole1 = new RequiresRoleAttribute("role1"); using (AuthorizationContext context = new AuthorizationContext(/*instance*/ null, "testOp", "testOpType", /*IServiceProvider*/ null, /*items*/ null)) { // user in role1 should be allowed AuthorizationResult result = requireRole1.Authorize(user1, context); Assert.AreSame(AuthorizationResult.Allowed, result, "Expected user in role1 to be authorized when only role1 is permitted"); // user in role2 should be denied result = requireRole1.Authorize(user2, context); Assert.AreNotSame(AuthorizationResult.Allowed, result, "Expected user in role2 to be denied when only role1 is permitted"); // Denial error message should reflect default plus operation string expectedMessage = String.Format(CultureInfo.CurrentCulture, Resource.AuthorizationAttribute_Default_Message, context.Operation); Assert.AreEqual(expectedMessage, result.ErrorMessage, "Expected to see default denial error message"); // user in role1 should be allowed if role1 + role2 + role3 are permitted RequiresRoleAttribute requireRole123 = new RequiresRoleAttribute(new string[] { "role1", "role2", "role3" }); result = requireRole123.Authorize(user1, context); Assert.AreSame(AuthorizationResult.Allowed, result, "Expected user1 in role1 to be authorized when role1, role2, and role3 are all permitted"); // user is in multiple roles (1, 2, and 3) should be allowed if any of these 3 roles are allowed IPrincipal user13 = this.CreateIPrincipal("user1", "role1", "role3"); result = requireRole123.Authorize(user13, context); Assert.AreSame(AuthorizationResult.Allowed, result, "Expected user1 in role1 and role3 to be authorized when role1, role2, and role3 are all permitted"); // user is in none of the required roles RequiresRoleAttribute requireRole567 = new RequiresRoleAttribute(new string[] { "role5", "role6", "role7" }); result = requireRole567.Authorize(user1, context); Assert.AreNotSame(AuthorizationResult.Allowed, result, "Expected user in role1 to be denied when only roles 5, 6, and 7 are allowed"); } }
/// <summary> /// Determines whether the given <paramref name="principal"/> is authorized to perform the operation /// specified by given <paramref name="authorizationContext"/>. /// </summary> /// <remarks>This method returns <see cref="AuthorizationResult.Allowed"/> only when the <paramref name="principal"/> /// is authenticated and belongs to at least one of the roles specified in <see cref="Roles"/>. /// <para> /// To require the principal to belong to multiple roles, multiple <see cref="RequiresRoleAttribute"/> /// custom attributes should be used on the respective operation. /// </para> /// </remarks> /// <param name="principal">The <see cref="IPrincipal"/> to authorize.</param> /// <param name="authorizationContext">The <see cref="AuthorizationContext"/> in which authorization is required.</param> /// <returns>A <see cref="AuthorizationResult"/> indicating whether or not the <paramref name="principal"/> is authorized. /// The value <see cref="AuthorizationResult.Allowed"/> indicates authorization is granted. Any other value /// indicates it has been denied.</returns> protected override AuthorizationResult IsAuthorized(IPrincipal principal, AuthorizationContext authorizationContext) { if (this._roles.Count == 0) { throw new InvalidOperationException(Resource.RequiresRoleAttribute_MustSpecifyRole); } if (principal.Identity != null && principal.Identity.IsAuthenticated) { // the user has to be in at least one of the roles foreach (string role in this._roles) { if (principal.IsInRole(role)) { return AuthorizationResult.Allowed; } } } return new AuthorizationResult(this.FormatErrorMessage(authorizationContext.Operation)); }
// Helper method to validate all forms of AuthorizationContext honor ServiceContainer public void Validate_AuthorizationContext_ServiceContainer(AuthorizationContext context) { // Asking for a ServiceContainer creates one IServiceContainer container = context.GetService(typeof(IServiceContainer)) as IServiceContainer; Assert.IsNotNull(container, "Expected lazily created ServiceContainer"); // The ServiceContainer should work. Add a service, test it, and remove it Guid guid = Guid.NewGuid(); container.AddService(typeof(Guid), guid); object service = container.GetService(typeof(Guid)); Assert.AreEqual(guid, service, "ServiceContainer did not honor addService"); container.RemoveService(typeof(Guid)); service = container.GetService(typeof(Guid)); Assert.IsNull(service, "ServiceContainer did not honor removeService"); }
protected override AuthorizationResult IsAuthorized(IPrincipal principal, AuthorizationContext authorizationContext) { return (principal.Identity != null && principal.Identity.IsAuthenticated && string.Equals(this._userName, principal.Identity.Name, StringComparison.InvariantCultureIgnoreCase)) ? AuthorizationResult.Allowed : new AuthorizationResult(this.FormatErrorMessage(authorizationContext.Operation)); }
/// <summary> /// Determines whether the given <paramref name="principal"/> is authorized to perform the operation /// specified by given <paramref name="authorizationContext"/>. /// </summary> /// <remarks> /// This method returns <see cref="AuthorizationResult.Allowed"/> only when the <paramref name="principal"/> /// is authenticated. /// </remarks> /// <param name="principal">The <see cref="IPrincipal"/> to authorize.</param> /// <param name="authorizationContext">The <see cref="AuthorizationContext"/> in which authorization is required.</param> /// <returns>A <see cref="AuthorizationResult"/> indicating whether or not the <paramref name="principal"/> is authorized. /// The value <see cref="AuthorizationResult.Allowed"/> indicates authorization is granted. Any other value /// indicates it has been denied.</returns> protected override AuthorizationResult IsAuthorized(IPrincipal principal, AuthorizationContext authorizationContext) { return (principal.Identity != null && principal.Identity.IsAuthenticated) ? AuthorizationResult.Allowed : new AuthorizationResult(this.FormatErrorMessage(authorizationContext.Operation)); }
/// <summary> /// Implementation specific method to determine whether the given <paramref name="principal"/> /// is authorized to perform a specific operation described by /// the given <paramref name="authorizationContext"/>. /// </summary> /// <remarks>This protected abstract method contains the implementation-specific logic for this particular /// subclass of <see cref="AuthorizationAttribute"/>. It is invoked strictly by the public <see cref="Authorize"/> method. /// </remarks> /// <param name="principal">The <see cref="IPrincipal"/> to be authorized.</param> /// <param name="authorizationContext">The <see cref="AuthorizationContext"/> describing the context in which /// authorization has been requested.</param> /// <returns>An <see cref="AuthorizationResult"/> that indicates whether the operation is allowed or denied. /// A return of <see cref="AuthorizationResult.Allowed"/> indicates the operation is allowed. /// A return of any other non-null <see cref="AuthorizationResult"/> indicates the request has been denied. /// The user visible error message for the denial is found in <see cref="AuthorizationResult.ErrorMessage"/> /// </returns> protected abstract AuthorizationResult IsAuthorized(IPrincipal principal, AuthorizationContext authorizationContext);
protected override AuthorizationResult IsAuthorized(IPrincipal principal, AuthorizationContext authorizationContext) { Assert.IsNotNull(principal, "Principal was null when custom authorization attribute was called"); Assert.IsNotNull(authorizationContext, "AuthorizationContext was null when custom authorization attribute was called"); Assert.IsFalse(string.IsNullOrEmpty(authorizationContext.Operation), "Operation was blank when custom authorization attribute was called"); Assert.IsFalse(string.IsNullOrEmpty(authorizationContext.OperationType), "OperationType was blank when custom authorization attribute was called"); if (!string.IsNullOrEmpty(this.ExpectedOperation)) { Assert.AreEqual(this.ExpectedOperation, authorizationContext.Operation, "AuthContext.Operation was not correct when attribute was evaluated"); } if (!string.IsNullOrEmpty(this.ExpectedOperationType)) { Assert.AreEqual(this.ExpectedOperationType, authorizationContext.OperationType, "AuthContext.OperationType was not correct when attribute was evaluated"); } bool isInvoke = authorizationContext.OperationType.Equals("Invoke"); AuthorizationTestEntity entity = authorizationContext.Instance as AuthorizationTestEntity; object instanceType = null; bool haveType = authorizationContext.Items.TryGetValue(typeof(Type), out instanceType); Assert.IsTrue(haveType, "Did not find entity type element in Items for " + authorizationContext.Operation); // Invokes don't guarantee the Type in the dictionary Assert.IsTrue(isInvoke || instanceType != null, "Entity type was null in Items diction for an Invoke"); bool deny = ((!string.IsNullOrEmpty(this.DenyOperation) && this.DenyOperation.Equals(authorizationContext.Operation)) || (!string.IsNullOrEmpty(this.DenyOperationType) && this.DenyOperationType.Equals(authorizationContext.OperationType)) || (!string.IsNullOrEmpty(this.DenyInstanceValue) && entity != null && this.DenyInstanceValue.Equals(entity.TheValue))); return deny ? string.IsNullOrEmpty(this.DenyMessage) ? new AuthorizationResult(this.FormatErrorMessage(authorizationContext.Operation)) : new AuthorizationResult(this.DenyMessage) : AuthorizationResult.Allowed; }
public void AuthorizationContext_Ctor_From_Template() { IServiceProvider serviceProvider = new AuthorizationContextServiceProvider(); using (AuthorizationContext template = new AuthorizationContext(serviceProvider)) { // Put a known value in the template's dictionary IDictionary<object, object> items = template.Items; Assert.IsNotNull(items, "template did not autocreate Items"); items["mockItem"] = "mockValue"; string instance = "mockEntity"; // type is only required to be object string operation = "testOp"; string operationType = "Query"; // Call template-based ctor using (AuthorizationContext context = new AuthorizationContext(instance, operation, operationType, template)) { // Instance and Operation should be what the ctor set Assert.AreEqual(instance, context.Instance, "AuthorizationContext.Instance property failure"); Assert.AreEqual(operation, context.Operation, "AuthorizationContext.Operation property failure"); Assert.AreEqual(operationType, context.OperationType, "AuthorizationContext.Operation property failure"); // Verify context delegates back to template's service provider string mockStringService = (string)context.GetService(typeof(string)); Assert.AreEqual("mockStringService", mockStringService, "AuthorizationContext.GetService() failed to respect input service provider"); // The items param should have been cloned, so verify it has the same content Assert.IsNotNull(context.Items, "AuthorizationContext.Items property failure"); Assert.IsTrue(context.Items.ContainsKey("mockItem"), "AuthorizationContext.Items failed to clone input items"); Assert.AreEqual("mockValue", context.Items["mockItem"], "AuthorizationContext.Items failed to set initial value correctly"); // Add item to original. The snapshot in the context should be unaffected. items["mockItem2"] = "mockValue2"; Assert.IsFalse(context.Items.ContainsKey("mockItem2"), "AuthorizationContext items should have copied snapshot input Items"); // Add an item to the context's Items to verify it is mutable context.Items["mockItem3"] = "mockValue3"; Assert.IsTrue(context.Items.ContainsKey("mockItem3") && (string)context.Items["mockItem3"] == "mockValue3", "Could not modify AuthorizationContext.Items"); // Share logic to validate ServiceContainer this.Validate_AuthorizationContext_ServiceContainer(context); } } }
// Helper method to validate templates behavior public void Validate_AuthorizationContext_Template(AuthorizationContext context) { // Asking for Items is permitted and lazily creates a dictionary IDictionary<object, object> items = context.Items; Assert.IsNotNull(items, "Expected Items to lazily initialize"); // Asking for Instance or Operation on a template should throw string expectedMessage = DataAnnotationsResources.AuthorizationContext_Template_Only; ExceptionHelper.ExpectInvalidOperationException(() => { var ignored = context.Instance; }, expectedMessage); ExceptionHelper.ExpectInvalidOperationException(() => { var ignored = context.Operation; }, expectedMessage); ExceptionHelper.ExpectInvalidOperationException(() => { var ignored = context.OperationType; }, expectedMessage); }
public bool IsAuthorized(AuthorizationContext authorizationContext) { return (UserPermissions & authorizationContext.ToPermissions()) != 0; }
/// <summary> /// Initalizes a new instance of the <see cref="AuthorizationContext"/> class from a template that can be used for authorization. /// </summary> /// <remarks> /// The specified <paramref name="authorizationContext"/> will be used as the new instance's /// <see cref="IServiceProvider"/>, and a snapshot of its <see cref="Items"/> will be captured. /// </remarks> /// <param name="instance">Optional object instance.</param> /// <param name="operation">Name of the operation requiring authorization, such as "GetEmployees".</param> /// <param name="operationType">Kind of the operation requiring authorization, such as "Query".</param> /// <param name="authorizationContext">An existing <see cref="AuthorizationContext"/> to use as a template.</param> /// <exception cref="ArgumentNullException">When <paramref name="operation"/> or <paramref name="operationType"/> is <c>null</c> or empty /// or <paramref name="authorizationContext"/> is <c>null</c>.</exception> public AuthorizationContext(object instance, string operation, string operationType, AuthorizationContext authorizationContext) : this((IServiceProvider) authorizationContext) { if (authorizationContext == null) { throw new ArgumentNullException("authorizationContext"); } // We use the _items field rather than the property to preserve the lazy instantiation semantics if it's null this.Setup(instance, operation, operationType, authorizationContext._items); }