Authorizing Access to User Data

Authorizing Access to User Data

Intro

Applications sometimes need to work with user information that is stored within the Curity Identity Server but not returned in tokens. Example scenarios might include an administrator viewing a list of all users, or an individual user updating their email address in an Edit Profile screen.

Access to user information also needs to be authorized, and this involves business rules, which will vary depending on your use case. This type of domain specific logic requires the same flexibility as the use of Scopes and Claims in your own APIs.

Enabling User Management

The User Management Guide provides full details on administering users, and the process starts by creating a User Management Profile. You then decide whether to expose endpoints for SCIM, GraphQL or both:

GraphQL Endpoint

You also need to configure an authorization manager, to determine which user data can be accessed, and the operations allowed on it. If required, you can create multiple user management profiles, each of which uses a different authorization manager.

Authorization Manager

Coarse Grained Access

The following configuration could be used for a simple portal application, and is based on a Groups Authorization Manager. The client application must use an accounts scope that is supplied in its authentication redirect. The access token returned to it can then be sent to GraphQL or SCIM endpoints to retrieve user information:

Coarse Grained Access

Not all users of the portal app will always have the same access though, so the runtime user management rights associated to each user is represented by a groups claim. In the portal application, users with a groups=admin claim would be able to perform user management operations, whereas other users would be denied access.

Fine Grained Access

In your own APIs, you will receive scopes and claims, then perform authorization in your data access code. This might involve denying access completely, filtering collections, or returning a subset of fields for each resource. When getting user information from the Curity Identity Server, you are not writing the data access code, yet fine grained access still needs to be managed.

Use Cases

The groups authorization manager does not deal with more granular access, such as the use cases listed below. To manage these, a more powerful option is needed:

Use CaseDescription
Self accessA user can only gain access to user data for their own account
Profile full accessA user can read or write their own profile information, such as name and email
Read or write only accessThe user can update their password but not read it
Deny accessThe user cannot read information about their account that is set by another party, such as roles

Attribute Authorization Manager

Starting in version 7.3 of the Curity Identity Server, the Attribute Authorization Manager enables you to implement the above use cases. This is composed of rule lists containing rules, where each rule acts like an Access Control List (ACL) for a particular area of a user's identity. In the following screenshot a user can change their name and email, if for example these values change due to marriage:

Example Rule

An overall rule list can set rules for an entire user identity. In the following screenshot, a number of rules have been defined to satisfy the use cases listed above:

Example Rule List

If required, more complex parts of the user identity can be managed in the same way, including the user's registered devices and dynamically registered clients.

Restricting Access

The rule list is also where properties of the incoming access token are configured, as the entry point to using GraphQL or SCIM. The following example simply requires an access token with an accounts scope, in the same way as the groups authorization manager described earlier. It is also possible to express more advanced rules based on claims in the access token:

Restricting Access

Restricting Results

Finally you can say how the data will be returned. The Require Subject Match options is used when you want to restrict users to only accessing their own account information. The default actions are applied when user details are selected that do not match any of the configured rules:

Enforcement Restrictions

Rule Evaluation

As for any ACL based system, it is possible to create complex setups and for multiple rules to conflict. In this case the first match wins, and the following behavior is also enforced. In most normal scenarios the behavior will be intuitive:

  • For write operations all attributes must be Allowed in order to prevent inconsistent mutations
  • For read operations any Denied attributes are filtered out of responses

Example Read Operation

In the following GraphQL query, with the example rules listed above, the application is trying to read the following values, where the displayName and roles fields have been configured in Deny rules:

query findAccount
{
  accountByUserName(userName: "demouser") {
    id
    name {
      givenName
      familyName
    }
    displayName
    emails {
      value
    }
    roles {
      value
    }
  }
}

In the query results, the displayName and roles fields have been filtered out of results, and their true values are not returned:

{
  "data": {
    "accountByUserName": {
      "id": "c02d2dde-ee25-11eb-9535-0242ac130005",
      "name": {
        "givenName": "Demo",
        "familyName": "User"
      },
      "displayName": null,
      "emails": [
        {
          "value": "demo@user.com"
        }
      ],
      "roles": []
    }
  }
}

Example Write Operation

In the following GraphQL mutation, the application is trying to update the user's password, which is allowed by a rule, whereas displayName is not used in any rule, and the Default Allow Write setting is not configured:

mutation updateAccount
{
  updateAccountById(input: {
    accountId: "c02d2dde-ee25-11eb-9535-0242ac130005",
    fields: {
      password: "Password1"
      displayName: "Unauthorized update"
    }
  }) {
    account {
      name {
        givenName
        familyName
      }
      displayName
      emails {
        value
      }
    }
  }
}

This results in all updates being rejected with the following response:

{
  "data": {
    "updateAccountById": null
  },
  "errors": [
    {
      "message": "Attribute 'account.displayName' is forbidden for 'UPDATE'.",
      "locations": [],
      "extensions": {
        "classification": "authorization-error"
      }
    }
  ]
}

Video

The following video provides a visual walkthrough on securely accessing user account data from applications:

Conclusion

Attribute based authorization enables you to take finer control over user management, to enable additional use cases. Access to user resources is firstly based on claims and scopes, to provide the Curity Identity Server with the runtime input about the current application and user. Rules and rule lists are then processed against this input, to produce full access control.