xaf-security

XAF Security System - SecurityStrategyComplex, role-based access control, TypePermission/ObjectPermission/MemberPermission, PermissionSettingHelper, authentication types (Standard, ActiveDirectory, OAuth2 v24.2+), programmatic permission checks via ISecurityStrategyBase, SecurityOperations constants, DenyAllByDefault policy, JWT Web API integration, custom ApplicationUser/Role classes, Updater seeding. Use when implementing security, roles, permissions or authentication in DevExpress XAF.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "xaf-security" with this command: npx skills add kashiash/xaf-skills/kashiash-xaf-skills-xaf-security

XAF: Security System

Overview

XAF Security System provides role-based access control (RBAC) via SecurityStrategyComplex. It controls:

  • Authentication — who can log in
  • Authorization — what they can see and do (type/object/member level)
  • ORM-level filtering: queries auto-modified so users only retrieve permitted records
  • UI: navigation items, editors, actions hidden/disabled based on permissions

Setup in Program.cs (ASP.NET Core Blazor)

builder.Services.AddXaf(builder.Configuration, b => {
    b.UseApplication<MyBlazorApplication>();
    b.AddObjectSpaceProviders(providers => {
        providers.UseEntityFramework(ef => {
            ef.DefaultDatabaseConnection("Default", p => p.UseDbContext<MyDbContext>());
        });
    });

    b.Security
        .UseIntegratedMode(options => {
            options.RoleType = typeof(PermissionPolicyRole);
            options.UserType = typeof(ApplicationUser);
        })
        .AddPasswordAuthentication(options => {
            options.IsSupportChangePassword = true;
        });
});

WinForms:

winApplication.Security = new SecurityStrategyComplex(
    typeof(ApplicationUser),
    typeof(PermissionPolicyRole),
    new AuthenticationStandard());

Authentication Types

TypeMethodUse Case
Username + PasswordAddPasswordAuthenticationStandard apps
Windows / ADAddWindowsAuthenticationInternal enterprise, SSO
OAuth2 / Entra IDAddOAuth2Authentication (v24.2+)Cloud SaaS, Azure AD
MixedCombine multiple .Add*() callsLocal + external providers

Active Directory

b.Security
    .UseIntegratedMode(options => {
        options.RoleType = typeof(PermissionPolicyRole);
        options.UserType = typeof(ApplicationUser);
        options.NewUserRoleName = "Default";
    })
    .AddWindowsAuthentication(options => {
        options.CreateUserAutomatically();
    });

OAuth2 / Entra ID (v24.2+)

b.Security
    .UseIntegratedMode(options => {
        options.RoleType = typeof(PermissionPolicyRole);
        options.UserType = typeof(ApplicationUser);
    })
    .AddPasswordAuthentication()
    .AddOAuth2Authentication(options => {
        options.Providers.AddMicrosoftAccount(entra => {
            entra.ClientId = builder.Configuration["AzureAd:ClientId"]!;
            entra.ClientSecret = builder.Configuration["AzureAd:ClientSecret"]!;
            entra.TenantId = builder.Configuration["AzureAd:TenantId"]!;
        });
        options.CreateUserAutomatically();
    });

v24.2: OAuth2 preview. v25.1: stabilized API, Google/GitHub providers added.


Permission Model

TypeScopeCriteria
TypePermissionEntire entity classNo
ObjectPermissionSpecific recordsYes (criteria string/lambda)
MemberPermissionIndividual propertyYes (combined with object criteria)

SecurityOperations Constants

SecurityOperations.Read              // "Read"
SecurityOperations.Write             // "Write"
SecurityOperations.Create            // "Create"
SecurityOperations.Delete            // "Delete"
SecurityOperations.Navigate          // "Navigate"
SecurityOperations.FullAccess        // "Create;Read;Write;Delete;Navigate"
SecurityOperations.CRUDAccess        // "Create;Read;Write;Delete"
SecurityOperations.ReadOnlyAccess    // "Read;Navigate"
SecurityOperations.ReadWriteAccess   // "Read;Write"

PermissionSettingHelper — Key Methods

using DevExpress.ExpressApp.Security;

// Type-level
role.AddTypePermission<Order>(SecurityOperations.Read, SecurityPermissionState.Allow);
role.AddTypePermission(typeof(Order), SecurityOperations.FullAccess, SecurityPermissionState.Allow);

// Object-level with criteria string
role.AddObjectPermission<Order>(
    SecurityOperations.ReadWriteAccess,
    "[AssignedTo.UserName] = CurrentUserId()",
    SecurityPermissionState.Allow);

// Object-level with lambda
role.AddObjectPermissionFromLambda<Order>(
    SecurityOperations.ReadWriteAccess,
    o => o.Status == OrderStatus.Draft,
    SecurityPermissionState.Allow);

// Member-level: deny write on specific field
role.AddMemberPermission<Employee>(
    SecurityOperations.Write,
    nameof(Employee.Salary),
    null,   // null = all records
    SecurityPermissionState.Deny);

Programmatic Role Setup (Updater.cs)

public override void UpdateDatabaseAfterUpdateSchema() {
    base.UpdateDatabaseAfterUpdateSchema();

    // Admin Role
    var adminRole = ObjectSpace.FirstOrDefault<PermissionPolicyRole>(r => r.Name == "Administrators");
    if (adminRole == null) {
        adminRole = ObjectSpace.CreateObject<PermissionPolicyRole>();
        adminRole.Name = "Administrators";
        adminRole.IsAdministrative = true; // bypasses ALL permission checks
    }

    // Users Role (deny-all + specific grants)
    var userRole = ObjectSpace.FirstOrDefault<PermissionPolicyRole>(r => r.Name == "Users");
    if (userRole == null) {
        userRole = ObjectSpace.CreateObject<PermissionPolicyRole>();
        userRole.Name = "Users";
        userRole.PermissionPolicy = SecurityPermissionPolicy.DenyAllByDefault;

        userRole.AddTypePermission<Order>(SecurityOperations.ReadOnlyAccess, SecurityPermissionState.Allow);
        userRole.AddObjectPermission<Order>(
            SecurityOperations.Write,
            "[Owner.UserName] = CurrentUserId()",
            SecurityPermissionState.Allow);
    }

    // Admin User
    var adminUser = ObjectSpace.FirstOrDefault<ApplicationUser>(u => u.UserName == "Admin");
    if (adminUser == null) {
        adminUser = ObjectSpace.CreateObject<ApplicationUser>();
        adminUser.UserName = "Admin";
        adminUser.SetPassword("");
        adminUser.Roles.Add(adminRole);
    }

    ObjectSpace.CommitChanges();
}

Permission Policies

PolicyBehavior
AllowAllByDefaultGrants all unless explicitly denied
DenyAllByDefaultDenies all unless explicitly allowed (production recommended)
ReadOnlyAllByDefaultAllows Read/Navigate; denies CUD unless granted

Checking Permissions in Code

Dependency Injection (recommended)

public class MyService {
    readonly ISecurityStrategyBase _security;
    public MyService(ISecurityStrategyBase security) => _security = security;

    public bool CanCreateOrder() =>
        _security.IsGranted(new PermissionRequest(typeof(Order), SecurityOperations.Create));
}

Shorthand Extensions

using DevExpress.ExpressApp.Security;

bool canRead   = security.CanRead(typeof(Order));
bool canCreate = security.CanCreate(typeof(Order));
bool canWrite  = security.CanWrite(typeof(Order));
bool canDelete = security.CanDelete(typeof(Order));

In Controllers

protected override void OnActivated() {
    base.OnActivated();
    var security = Application.ServiceProvider.GetRequiredService<ISecurityStrategyBase>();
    if (!security.CanCreate(typeof(Order)))
        NewAction.Active["Permission"] = false;
}

Custom Security Objects

// EF Core custom user
[DefaultClassOptions]
public class ApplicationUser : PermissionPolicyUser, ISecurityUserWithLoginInfo {
    public ApplicationUser(DbContext objectSpace) : base(objectSpace) { }

    public virtual string? Department { get; set; }
    public virtual DateTime? LastLoginDate { get; set; }

    IEnumerable<ISecurityUserLoginInfo> ISecurityUserWithLoginInfo.LoginProviderInfos
        => LoginProviderInfos.OfType<ISecurityUserLoginInfo>();
    public virtual IList<ApplicationUserLoginInfo> LoginProviderInfos { get; set; }
        = new List<ApplicationUserLoginInfo>();
}

// Register:
b.Security.UseIntegratedMode(options => {
    options.UserType = typeof(ApplicationUser);
    options.RoleType = typeof(ExtendedRole); // optionally custom role
});

Object-Level Security

XAF rewrites ORM queries automatically — no extra filtering needed:

// Returns only permitted records automatically
var myOrders = objectSpace.GetObjects<Order>();
  • EF Core: additional WHERE clauses injected via secured DbContext
  • XPO: criteria applied at session/unit-of-work level

Web API Integration

b.Security
    .UseIntegratedMode(options => { ... })
    .AddPasswordAuthentication();

builder.Services.AddAuthentication()
    .AddJwtBearer(options => {
        options.TokenValidationParameters = new TokenValidationParameters {
            ValidIssuer = config["Jwt:Issuer"],
            ValidAudience = config["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(config["Jwt:Key"]!))
        };
    });

Token endpoint: POST /api/Authentication/Authenticate

{ "userName": "Admin", "password": "" }

Use as: Authorization: Bearer <token> All OData endpoints automatically apply XAF security.


Common Patterns

// Deny-all + grant specific
role.PermissionPolicy = SecurityPermissionPolicy.DenyAllByDefault;
role.AddTypePermission<Order>(SecurityOperations.ReadOnlyAccess, SecurityPermissionState.Allow);

// Admin bypass
adminRole.IsAdministrative = true;

// Per-user row-level security
role.AddObjectPermission<Task>(
    SecurityOperations.ReadWriteAccess,
    "[AssignedUser.UserName] = CurrentUserId()",
    SecurityPermissionState.Allow);

Source Links

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

xaf-office

No summary provided by upstream source.

Repository SourceNeeds Review
General

xaf-winforms-ui

No summary provided by upstream source.

Repository SourceNeeds Review
General

xaf-deployment

No summary provided by upstream source.

Repository SourceNeeds Review
General

xaf-blazor-ui

No summary provided by upstream source.

Repository SourceNeeds Review