Skip to content

Securing the Generated Service

Consider adding security measures to your generated OData service to control access.

You can secure the generated OData services by:

  1. Authenticating each user's identity.

  2. Authorizing each user's data access.

  3. Ensuring the confidentiality of data that's passed over the network.

Caution

If you omit the -login option during service generation, the generated OData service doesn't check a user's identity or restrict a user's data access. Nor does it guarantee that data passed over the network is encrypted (via HTTPS). Apart from exceptional circumstances, such as public-access read-only services, you should configure a production application for authentication, authorization, and confidentiality. This helps to ensure compliance with the EU General Data Protection Regulation or other applicable regulations.

Authentication

Using the -login option, specify XSUAA for Cloud Foundry (or another option supported by the target environment) to ensure that only authenticated users can access the service, it also supports X509 for Principal Propagation authentication for on-premise server.

Note

The generated service uses the login-config element within the generated web.xml to enforce authentication, however, for X509 authentication the login-config element will not be added (a servlet filter will be generated in that case).

Authorization

Specify the Security.Roles annotation for security roles that might not be referenced in other security annotations, but might be referenced in runtime checks using custom code, for example, when you are implementing row-level authorization.

Specify the Security.ServiceUserRoles annotation (or rely on the default Everyone role which matches all authenticated users) to ensure that only authorized users will be able to access the main OData service To authorize a subset of all authenticated users, specify a role name such as ServiceUser.

Specify the Security.ViewMetricsRoles annotation (or rely on the default ViewMetrics role) to ensure that only authorized administrators can access the embedded metrics service.

Example:

<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
    <edmx:Reference Uri="vocabularies/com.sap.cloud.server.odata.sql.v1.xml">
        <edmx:Include Alias="Security" Namespace="com.sap.cloud.server.odata.security.v1"/>
    </edmx:Reference>
    <edmx:DataServices>
        <Schema Namespace="example" xmlns="http://docs.oasis-open.org/odata/ns/edm" Alias="Self">
            ...
            <EntityContainer Name="ExampleService">
                <Annotation Term="Security.Roles">
                    <Collection>
                        <String>Manager</String>
                    </Collection>
                </Annotation>
                <Annotation Term="Security.ServiceUserRoles">
                    <Collection>
                        <String>Employee</String>
                    </Collection>
                </Annotation>
                <Annotation Term="Security.ViewMetricsRoles">
                    <Collection>
                        <String>Administrator</String>
                    </Collection>
                </Annotation>
            </EntityContainer>
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>

Note

The generated service uses security-constraint elements within the generated web.xml to enforce authorization.

Fine-Grained Authorization

All authorized users have permission to create, read, update, and delete any data. The following section describe how to achieve more fine-grained authorization controls.

Method-Level Authorization

Reference the Security annotation vocabulary in the CSDL XML file to restrict access to data methods (action imports, function imports), and apply the Security.InvokeRoles annotation term from that vocabulary to the data methods.

Example:

<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
    <edmx:Reference Uri="vocabularies/com.sap.cloud.server.odata.sql.v1.xml">
        <edmx:Include Alias="Security" Namespace="com.sap.cloud.server.odata.security.v1"/>
    </edmx:Reference>
    <edmx:DataServices>
        <Schema Namespace="example" xmlns="http://docs.oasis-open.org/odata/ns/edm" Alias="Self">
            ...
            <Action Name="SetSalaryAction">
                ...
            </Action>
            <EntityContainer Name="ExampleService">
                ...
                <ActionImport Name="SetSalary" Action="Self.SetSalaryAction">
                    <Annotation Term="Security.InvokeRoles">
                        <Collection>
                            <String>Manager</String>
                        </Collection>
                    </Annotation>
                </ActionImport>
            </EntityContainer>
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>

A user needs only one of the permitted roles to be allowed access. Specifying an empty roles collection in the roles annotation means nobody can access the resource.

Table-Level Authorization

Reference the Security annotation vocabulary in the CSDL XML file to restrict access to entity sets (database tables) and apply the annotation terms from that vocabulary to the entity sets.

Example:

<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
    <edmx:Reference Uri="vocabularies/com.sap.cloud.server.odata.sql.v1.xml">
        <edmx:Include Alias="Security" Namespace="com.sap.cloud.server.odata.security.v1"/>
    </edmx:Reference>
    <edmx:DataServices>
        <Schema Namespace="example" xmlns="http://docs.oasis-open.org/odata/ns/edm" Alias="Self">
            ...
            <EntityType Name="Customer">
                ...
            </EntityType>
            <EntityType Name="Order">
                ...
            </EntityType>
            <EntityContainer Name="ExampleService">
                <EntitySet Name="Customers" EntityType="Self.Customer">
                    <Annotation Term="Security.ReadRoles">
                        <Collection>
                            <String>ViewCustomer</String>
                        </Collection>
                    </Annotation>
                    <Annotation Term="Security.WriteRoles">
                        <Collection>
                            <String>EditCustomer</String>
                        </Collection>
                    </Annotation>
                    <NavigationPropertyBinding Path="Orders" Target="Orders"/>
                </EntitySet>
                ...
            </EntityContainer>
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>

Available annotation terms for entity set security include the following:

  • Security.ReadWriteRoles – a collection of roles permitted for read or write access, if not overridden by the more specific Security.ReadRoles, Security.WriteRoles, Security.CreateRoles, Security.UpdateRoles or Security.DeleteRoles.

  • Security.ReadRoles – a collection of security roles permitted for read access.

  • Security.WriteRoles – a collection of security roles permitted for write access, if not overridden by the more specific Security.CreateRoles, Security.UpdateRoles, or Security.DeleteRoles.

In each case, a user needs only one of the permitted roles to be allowed access. Specifying an empty roles collection in the roles annotation means nobody can access the resource. Additionally specifying the Security.ReadRoles, but not the Security.WriteRoles, causes nobody to have write access except as permitted by Security.CreateRoles, Security.UpdateRoles, or Security.DeleteRoles.

Row-Level Authorization

You may want to customize generated listener classes to implement row-level authorization. The simplest way to achieve this is to add code into a beforeQuery listener method to add extra filter conditions to the client-specified queries. Adding these query filters also prevents write access to the respective records.

For example, suppose there is an Employee entity type with a business rule that managers can access any employee's record, but regular employees can access only their own employee record. This might be coded in the EmployeeListener class.

@Override void beforeQuery(DataQuery query)
{
    if (!servlet.isUserInRole("Manager"))
    {
        // Add or extend query filter to employee's own record only.
        query.filter(Employee.email.equal(servlet.currentUser()));
    }
}

If it isn't feasible to add extra filter conditions to achieve the required level of row-level authorization, then you may need to customize the executeQuery method in the generated entity handler for the entity type to post-process the query results.

Note

Any security role name used in a servlet.isUserInRole check must reference at least one security roles annotation so that the role name is known at deployment time. Use the Security.Roles annotation, as shown in the authorization examples, if there are no other roles-related annotations that reference the required role name.

Column-Level Authorization

Customize generated listener classes to implement column-level authorization.

For example, suppose that only managers can update an employee's salary, but employees can update other details in their own employee records. In addition to the beforeQuery customization, this might be coded in the EmployeeListener class.

@Override void beforeSave(EntityValue entityValue)
{
    Employee entity = (Employee)entityValue;
    if (entity.isNewOrChanged(Employee.salary)
        && !servlet.isUserInRole("Manager"))
    {
        throw AccessDeniedException.cannotWrite(Employee.salary.getQualifiedName());
    }
}

Note

Any security role name used in a servlet.isUserInRole check must reference at least one security roles annotation so that the role name is known at deployment time. Use the Security.Roles annotation, as shown in the authorization examples, if there are no other roles-related annotations referencing the required role name.

Confidentiality

Using the -login option ensures the confidentiality of data passed over the network.

Note

The generated service uses the transport-guarantee element of CONFIDENTIAL within the generated web.xml to achieve confidentiality.

Local Apache TomEE Security

Please refer to the Apache TomEE Security documentation and Apache Tomcat Security documentation for detailed configuration instructions.

  • Configure TomEE for transport-level security.

  • Edit conf/tomcat-users.xml to create users and assign appropriate roles.

  • Your OData service should now be ready for secure access by regular users and administrators. Make sure to use an https URL when connecting.

Note: A local server is useful for basic security testing, but additional security testing should always be performed in the intended target environment.

See also: -http and -https options.

SAP Business Technology Platform Security

Use the security provided by the SAP Business Technology Platform to secure your generated OData service.

Note

The Develop Applications topic in the SAP Business Technology Platform documentation is a good starting point for additional information about SAP Business Technology Platform security.

SAP Business Technology Platform Security – Quick Setup

The MBT: Create tasks.json file command should have created a Visual Studio Code Task labeled setup-mobile-app which can setup the Mobile Application and Mobile Destination for secure mobile client connectivity.

Use Terminal > Run Task > setup-mobile-app in Visual Studio Code or SAP Business Application Studio.

In certain situations this task may request some additional manual steps to be taken.

Configure Role Collections and Trust Configuration as documented in the next section.

See Cloud Connector Setup for Mobile Clients for local or on-premise deployments.

SAP Business Technology Platform Security – Mobile Services

Use these security measures to keep your application secure in the SAP Mobile Services - Cloud Foundry environment.

The following instructions refer to the SAP Mobile Services Cockpit, and are subject to change if the cockpit UI changes.

SAP Business Technology Platform for Cloud Foundry usually requires a xsuaa service instance and application router creation in order to secure a deployed Java application. This is described in the next section. If deployed OData services are to be consumed by mobile applications and SAP Mobile Services for Cloud Foundry is available, the process can be simplified to the following steps.

  1. Using the SAP Mobile Services Cockpit, select Mobile Applications > Native/Hybrid > New.

  2. For ID and Name, enter the -application name that was selected for service generation.

  3. On the Info tab for your mobile application, select the + sign to the right of Assigned Features. Choose Mobile Connectivity and select OK.

  4. On the Mobile Connectivity Configuration tab, select the Create icon to create a destination.

  5. Enter your OData service root URL, then select No Rewriting as the rewrite mode.

  6. Skip the Custom Headers and Annotations dialog pages.

  7. Select Forward Authentication as the SSO mechanism, then select Finish.

  8. On the APIs tab for your mobile application, note the Destination URL, which is the URL that clients should use to access your OData service with authentication. Note that any attempts by clients to directly access the OData service (other than via the Destination URL) will encounter HTTP error 401.

  9. On the Security tab for your mobile application, select the Edit (pencil) icon to the right of Application Settings and choose the security configuration (Basic, SAML, or OAuth) that meets your organization's security requirements. You may be able to use Basic for testing purposes depending on your identity provider service. SAML works well with desktop browser clients. Using OAuth may require more client-side configuration.

  10. On the Security tab for your mobile application, select the Edit (pencil) icon to the right of XSUAA Settings. Select Browse to open the xs-security.json file from your application's project folder.

  11. Select OK to save the role settings.

  12. Consult the SAP Business Technology Platform documentation Security > Authorization and Trust Management > Developing Security Artifacts > Set Up Security Artifacts > Bind the XSUAA Service Instance to the Application. Bind the <app-name>-xsuaa service instance to your OData service.

  13. Restart your OData service so it recognizes the assigned xsuaa service instance.

  14. In the SAP Business Technology Platform Cockpit, navigate to your Cloud Foundry subaccount, then use Security > Role Collections to define one or more role collections. If your application uses the default ServiceUser and ViewMetrics roles, define a role collection for each one and add the corresponding role to it. Otherwise, define role collections in accordance with the roles you selected using OData annotations for authorization. For each role ServiceUser and ViewMetrics, highlight the role. Select Assign and in the pop-up specify your user id and select Assign. The ServiceUser role is for regular users of the service (that is, a regular user of the service must have this role in order to be permitted to use the service, unless the Everyone role has been enabled by default during service deployment). The ViewMetrics role is for administrators who want to view the service’s performance metrics. Regular users should not be permitted to view the metrics.

  15. In the SAP Business Technology Platform Cockpit, navigate to your Cloud Foundry subaccount, then select Security > Trust Configuration and select your identity provider to show the Role Collection Assignment page, where you can assign role collections to individual users. You may also need to edit the trust configuration named trust_mobile_services, and disable the Available for User Login option.

SAP Business Technology Platform Security – Cloud Foundry

Use these security measures to keep your application secure in the SAP Business Technology Platform - Cloud Foundry environment.

The following instructions refer to the SAP Business Technology Platform Cockpit, and are subject to change if the cockpit UI changes.

  1. Consult the SAP Business Technology Platform documentation topic Security > Authorization and Trust Management > Authorization and Trust Management in the Cloud Foundry Environment.

  2. Using the SAP Business Technology Platform Cockpit, navigate to your Cloud Foundry space, then use the Service Marketplace menu option to locate the xsuaa service.

  3. Select the xsuaa service, then select Instances, and select New Instance.

  4. In the Specify Parameters page of the wizard, select Browse and select the xs-security.json file that was generated in your project folder. This file defines the scopes and roles that are needed by the application.

  5. On the Assign Application page of the wizard, choose your deployed application.

  6. On the Confirm page of the wizard, choose an instance name (for example: my-app-xsuaa) and select Finish.

  7. Restart your OData service so it can recognize the assigned xsuaa service instance.

  8. Consult the SAP Business Technology Platform documentation Development > Applications in the Cloud Foundry Environment > Configure Application Router.

  9. Consult the SAP Business Technology Platform documentation Security > Authorization and Trust Management > Developing Security Artifacts > Set Up Security Artifacts > Bind the XSUAA Service Instance to the Application. Bind the xsuaa service instance to your application router (it was already bound to your OData service by the prior Assign Application step). Restart your application router.

  10. Configure Role Collections and Trust Configuration as documented in the previous section.

This following additional information may be helpful as you set up XSUAA:

  • When you create your service xsuaa instance make sure to specify application as the plan.

  • The generated xs-security-json defaults to dedicated as the tenant mode. Some Cloud Foundry landscape IDPs configure for "shared" tenant-mode. In that case, change it to shared before creating the XSUAA service instance.

  • In SAP Business Technology Platform Cockpit, the Trust Configuration and Role Collections require security administrator privileges, otherwise you can't see them.

    Your OData service is now ready for secure access by regular users and administrators.

Cloud Connector Setup for Mobile Clients

This section is only relevant for local or on-premise deployments of the generated OData service.

Once the SAP Business Technology Platform Security setup has been completed, there should exist in the SAP Mobile Services account a Mobile/Native application named <app-name>, and a Mobile Destination named app (or similar).

If the OData service was deployed locally (or on-premise), then the Mobile Destination should have the Use Cloud Connector checkbox enabled and should have a URL of the form http://<virtual-host>:<virtual-port>.

The recommended <virtual-host> is the <app-name> with all underscores ('_') replaced with hyphens ('-'). For example, if the <app-name> is my_app, then the <virtual-host> should be my-app. The recommended <virtual-port> is 80.

Set up SAP Cloud Connector with the selected Virtual Host name (e.g. my-app) and Virtual Port number (e.g. 80) and an Internal Host name and Internal Port number that match the local or on-premise host name and port number of the deployed OData service.

X509 Principal Propagation Authentication

Using the -login option specify X509 to enable Principal Propagation authentication.

Note

This option only supports an on-premise OData service.

In this scenario, it will setup Mutual Authentication between the SAP Cloud Connector and the on-premise OData service, however the on-premise OData service does not validate the Common Name from the client certificate. The SAP Cloud Connector will put a temporary user certificate in the HTTP request header ssl_client_cert, which contains the identity of an on-demand user. A filter in the on-premise OData service will decode this header and put the identity to the User Principal.

The following instructions are to configure the Principal Propagation authentication in SAP Mobile Services, SAP Cloud Connector and the on-premise OData service.

  • Firstly, configure the SAP Mobile Services. Create a new Application in Native/Hybrid Mobile Applications and assign the Mobile Connectivity feature, create a new Mobile Destination in the Mobile Connectivity feature, the SSO Mechanism/Authentication should be set to SAP Cloud Connector SSO in the Mobile Destination, for more information please refer to:

  • Secondly, configure the SAP Cloud Connector, setup trusts between SAP Business Technology Platform and SAP Cloud Connector, also setup the trusts between SAP Cloud Connector and back-end server, add corresponding Subaccount, configure the Access Control in Cloud To On-Premise section, for more information please refer to:

    • Connectivity (SAP Business Technology Platform Connectivity (Cloud Foundry environment))
  • Finally, setup the Mutual Authentication in the on-premise OData service, for more information please refer to the server documentation (e.g. for Apache Tomcat or TomEE).


Last update: November 18, 2021