Securing the Generated Service¶
Consider adding security measures to your generated OData service to control access.
You can secure the generated OData services by:
-
Authenticating each user's identity.
-
Authorizing each user's data access.
-
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.
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 service.
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 specificSecurity.ReadRoles
,Security.WriteRoles
,Security.CreateRoles
,Security.UpdateRoles
orSecurity.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 specificSecurity.CreateRoles
,Security.UpdateRoles
, orSecurity.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 service. 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.
-
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 – Mobile Services¶
Use these security measures to keep your application secure in the mobile services environment for Cloud Foundry.
The following instructions refer to the SAP mobile service 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 below. If these services are to be consumed by mobile
applications and SAP Mobile Services for Cloud Foundry is available, the process can be simplified to
these steps.
-
Using the SAP mobile service cockpit, select Mobile Applications > Native/Hybrid > New.
-
For ID and Name, enter the ID and name of your already deployed OData application with
router
appended (the application router cannot have the same name as the OData service). Select Save.The SAP mobile service cockpit creates an application router and
xsuaa
service instance. -
On the Info tab for your mobile application, select the + sign to the right of Assigned Features. Choose Mobile Connectivity and select OK.
-
On the Mobile Connectivity Configuration tab, select the Create icon to create a destination.
-
Enter your OData service root URL, then select No Rewriting as the rewrite mode.
-
Skip the Custom Headers and Annotations dialog pages.
-
Select Forward Authentication as the SSO mechanism, then select Finish.
-
On the APIs tab for your mobile application, note the Back End URL, which is the URL that clients should use to access your OData service via the application router.
-
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.
-
Enable CSRF Protection to prevent Cross-Site Request Forgery.
-
On the Security tab for your mobile application, select the Edit (pencil) icon to the right of Role Settings. Select Browse to open the
xs-security.json
file in your project folder. -
Select OK to save the role settings.
-
Navigate back to your Cloud Foundry subaccount, then use Security > Role Collections to define one or more role collections. If your application uses the default
ServiceUser
andViewMetrics
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 roleServiceUser
andViewMetrics
, highlight the role. Select Assign and in the pop-up specify your user id and select Assign. TheServiceUser
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). TheViewMetrics
role is for administrators who want to view the service’s performance metrics. Regular users should not be permitted to view the metrics. -
Navigate back 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.
-
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 OData service (it was already bound to your application router by the SAP mobile service cockpit). -
Restart your OData service so it recognizes the assigned
xsuaa
service instance.Your OData service should now be ready for secure access by regular users and administrators using the service root (back-end) URL shown on the APIs tab for your mobile application.
SAP Business Technology Platform Security – Cloud Foundry¶
Use these security measures to keep your application secure in the Cloud Foundry environment.
The following instructions refer to the SAP Business Technology Platform Cockpit, and are subject to change if the cockpit UI changes.
-
Consult the SAP Business Technology Platform documentation topic Security > Authorization and Trust Management > Authorization and Trust Management in the Cloud Foundry Environment.
-
Ensure that the Authentication Method
xsuaa
option was used during application generation. -
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. -
Select the
xsuaa
service, then select Instances, and select New Instance. -
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. -
On the Assign Application page of the wizard, choose your deployed application.
-
On the Confirm page of the wizard, choose an instance name (for example:
myapp-xsuaa
) and select Finish. -
Restart your OData service so it can recognize the assigned
xsuaa
service instance. -
Consult the SAP Business Technology Platform documentation Development > Applications in the Cloud Foundry Environment > Configure Application Router.
-
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. -
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 specifyapplication
as the plan. -
The generated
xs-security-json
defaults todedicated
as the tenant mode. Some Cloud Foundry landscape IDPs configure for "shared" tenant-mode. In that case, change it toshared
before creating the XSUAA service instance. -
In Cloud Foundry 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.
Consider using SAP Mobile Services as an intermediary with your OData service so that you can enable CSRF Protection to prevent Cross-Site Request Forgery.
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:
- Defining Connectivity (SAP Mobile Services (Cloud Foundry environment))
-
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).