WSScope

Specify security in the REST service via scopes.

Syntax

WSScope = "{ scope } [,...]"
Where WSScope is a comma-separated list of scopes and where:
  1. scope defines access permission for the resource.

Usage

You use this attribute to specify security via scopes forwarded from the Genero Application Server to the GWS REST service.

WSScope is an optional attribute.

Note: Testing your services with WSScope:
  • When testing your service in standalone mode without a GAS, the WSScope is not checked. However, when behind a GAS, the appropriate scope is required and you will need to deploy and secure the service with the Genero Identity Provider (GIP).
  • Alternatively, if you need to integrate Genero REST services security into your own environment system, you can also write your own delegate service to validate any kind of token, extract the scope from it, and forward it to the REST service.

You can set the WSScope attribute in the service information record of the module at the service level or in the ATTRIBUTES() clause of the REST function.

Example using WSScope in the information record at the service level

When the scope is set in the service information record, all REST functions in the Web service are executed if, and only if, the request contains a scope definition that matches the value in the WSScope attribute.
PUBLIC DEFINE serviceInfo RECORD ATTRIBUTE(WSInfo, WSScope="users.myservice")
  title STRING,
  description STRING,
  termOfService STRING,
  contact RECORD
    name STRING,
    url STRING,
    email STRING
    END RECORD,
    version STRING
  END RECORD = (
    title: "my service", 
    version: "1.0", 
    contact: ( email:"helpdesk@mysite.com") )
Note: The main purpose of the service information record (defined with the WSInfo attribute) is to document the REST service. If you are not setting the scope at the modular level here, the record is still needed to provide service information.

Example setting the WSScope in a REST function

If the call to a specific REST function requires user authentication, add the WSScope attribute in its ATTRIBUTES() clause.

For example, this function is only executed if the scope (WSScope) contains "dev.read". The GAS also needs to be started.

IMPORT com

TYPE profileType RECORD
     id INT,
     name VARCHAR(50),
     email VARCHAR(100)
   END RECORD
   
PUBLIC
DEFINE myError RECORD ATTRIBUTE(WSError="My error")
  code INTEGER,
  reason STRING
END RECORD

PUBLIC FUNCTION getUsersList()
  ATTRIBUTES (WSGet, 
              WSPath = "/users",
              WSDescription = "Get a list of all users, requires authentication",
              WSThrows = "400:Invalid,404:NotAvailable", 
              WSScope = "dev.read")
  RETURNS (
    DYNAMIC ARRAY ATTRIBUTE(WSName="Users",WSMedia="application/xml") OF profileType 
    ATTRIBUTE(XMLName="User") )

    DEFINE userList DYNAMIC ARRAY OF profileType
    WHENEVER ERROR continue
    DECLARE c2 CURSOR FOR SELECT * FROM users
    WHENEVER ERROR STOP
    CASE
    WHEN SQLCA.SQLCODE = 0
        # ... function code  ...
    OTHERWISE
        INITIALIZE userList TO NULL
        LET myError.reason = SFMT("SQL error:%1 [%2]",SQLCA.SQLCODE, SQLERRMESSAGE)
        CALL com.WebServiceEngine.SetRestError(400,myError)
    END CASE
    FREE c2
    RETURN userList
END FUNCTION

How to determine the scope names

When determining the names for the scopes, it is important to understand the role of scopes. You create a scope in the Identity Provider (IdP) system and assign it to a group or a user, so that the user or group member will get an access token containing the scope name, and be allowed to access an operation that specifies the same scope name using the WSScope attribute.

The names you choose can be a simple name (such as "readonly"), or it can use dot notation (such as "readonly.dev" and "readonly.user") to provide a logical hierarchy. The hierarchy approach is optional; it is purely provided to allow you to organize your scopes in a logical manner that makes sense to you. Your end user would still need to belong to groups that have either "readonly.dev" or "readonly.user" scope assigned to them, the ".dev" and ".user" extensions do not in themselves have any meaning to the IdP.

For example, you could create a service access list with the server name of "ReadOnly", with two scopes defined: "ReadOnly.dev" and "ReadOnly.user". You would then set the ReadOnly.dev scope to the resources to be accessible to developers, and the ReadOnly.user scope to the resources to be accessible to users only.

When determining scope names, it may also be helpful to think of the overall solution, which can be a complex system with many services all working together. You can evaluate the access needs of the various services and operations, and then identify the list of scopes that would allow you to provide (or restrict) access to your various groups of users.

In summary, there is no restriction on the names you choose for scopes. You can set them as you wish, depending on what you want to achieve.