Create an Application with SAP Java Buildpack 2
Create a simple Spring Boot application and enable services for it, by using SAP Java Buildpack 2 and Cloud Foundry Command Line Interface (cf CLI).
Overview
You will learn
- How to create a Spring Boot Java project
- How to create and deploy a simple “Hello World” application
- How to run authentication and authorization checks via the Authorization and Trust Management (XSUAA) service
Prerequisites
Prerequisites
- You have a trial or productive account for SAP Business Technology Platform (SAP BTP). If you don’t have such yet, you can create one so you can [try out services for free] (https://developers.sap.com/tutorials/btp-free-tier-account.html).
- You have created a subaccount and a space on Cloud Foundry Environment.
- [cf CLI] (https://help.sap.com/products/BTP/65de2977205c403bbc107264b8eccf4b/4ef907afb1254e8286882a2bdef0edf4.html) is installed locally.
- [npm] (https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) is installed locally.
- You have downloaded [
JDK for SapMachine 21] (https://sap.github.io/SapMachine/) and [installed] (https://github.com/SAP/SapMachine/wiki/Installation) it locally, configuring yourPATHandJAVA_HOMEenvironment variables. - You have [Apache Maven] (https://maven.apache.org/download.cgi) downloaded. To do that, go to Files and choose the
Binary zip archivelink. For this tutorial, we use version3.9.8. - [Install Maven] (https://maven.apache.org/install.html) - similar to JDK, configure your
PATHandMAVEN_HOMEvariables. - You have installed an integrated development environment. In this tutorial, we use [Visual Studio Code] (https://code.visualstudio.com/) but you can use a different one (Eclipse IDE or IntelliJ IDEA).
Steps
Intro
This tutorial will guide you through creating and setting up a simple Java application by using cf CLI. You will start by creating a Java project via Spring Boot, and then creating a web application that returns simple data โ a Hello World! message. This simple app will be invoked through a web microservice (application router). Finally, you will set authentication checks and an authorization role to properly access your web application.
First, you need to connect to the SAP BTP, Cloud Foundry environment with your trial or enterprise (productive) subaccount. Your Cloud Foundry URL depends on the region where the API endpoint belongs to. To find out which one is yours, see: [Regions and API Endpoints Available for the CF Environment] (https://help.sap.com/docs/btp/sap-business-technology-platform/regions-and-api-endpoints-available-for-cloud-foundry-environment)
In this tutorial, we use eu20 as an example.
Open a command-line console.
Set the Cloud Foundry API endpoint for your subaccount. Run the following command (using your actual region URL):
Bash/Shellcf api https://api.cf.eu20.hana.ondemand.comLog on to the SAP BTP, Cloud Foundry environment:
Bash/Shellcf loginWhen prompted, enter your user credentials. These are the email and password you have used to register your trial or productive SAP BTP account.
IMPORTANT: If the authentication fails, even though you’ve entered correct credentials, try [logging in via single sign-on] (https://help.sap.com/products/BTP/65de2977205c403bbc107264b8eccf4b/e1009b4aa486462a8951c4d499ce6d4c.html?version=Cloud).
Choose the org name and space where you want to create your application.
If you’re using a trial account, you don’t need to choose anything. You can use only one org name, and your default space is
dev.
RESULT
Details about your personal SAP BTP subaccount are displayed (API endpoint, user, organization, space).
Before creating an application, you need a Java project. For this tutorial, you can easily create one by using Spring Boot.
Open:
https://start.spring.ioFrom the configuration screen, choose
Maven Project, languageJava, and Spring Boot version3.5.x.From
Project Metadatasection, you need to do the following settings:Group:
com.exampleArtifact:
java-tutorialPackage name:
com.example.java-tutorialPackaging:
JarConfiguration:
YAMLJava:
21
Choose
Add Dependenciesand then selectSpring Web.Choose
Generate.A
java-tutorial.zipfile is generated. Save it on your local file system and then extract thejava-tutorialfolder.
RESULT
You have successfully created a basic Java project.
For this part, you need to configure your HelloWorld application, add an extra class, and a manifest.yml file.
Open
java-tutorialdirectory in a console client, and run:Bash/Shellmvn installThis command builds your Java project (as a Maven one).
From your Visual Studio Code, open the
java-tutorialfolder and create a filemanifest.ymlwith the following content:YAML--- applications: - name: helloworld random-route: true path: ./target/java-tutorial-0.0.1-SNAPSHOT.jar memory: 1024M buildpacks: - sap_java_buildpack_jakarta env: TARGET_RUNTIME: tomcat JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jdk.SAPMachineJDK']" JBP_CONFIG_SAP_MACHINE_JDK : "{ version: 21.+ }"The
manifest.ymlfile represents the configuration describing your application and how it will be deployed to Cloud Foundry.IMPORTANT: Make sure you don’t have another application with the name
helloworldin your space. If you do, use a different name and adjust the whole tutorial according to it.Navigate to
src\main\java\com\example\java_tutorialand open theJavaTutorialApplication.javafile.In the
public static void mainclass, add the following line:System.out.println("Hello World!");Your final Java code should look like this:
Javapackage com.example.java_tutorial; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class JavaTutorialApplication { public static void main(String[] args) { SpringApplication.run(JavaTutorialApplication.class, args); System.out.println("Hello World!"); } }Navigate to
...\java_tutorialand from its context menu, chooseNew Java File>Class.Enter
MainControllerand press theENTERkey. The new class appears in the project navigation.Replace its default content with the following code:
Javapackage com.example.java_tutorial; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(path = "") public class MainController { @GetMapping(path = "") public ResponseEntity<String> getDroneMedications() { return new ResponseEntity<String>("Hello World!", HttpStatus.OK); } }
RESULT
Your Java project is complete and your application is ready to be deployed.
Test your project locally first. To do that, in the Visual Studio Code, right-click on
JavaTutorialApplication.javaand chooseRun Java.The final result displayed in the
Terminaltab should be: Hello World!Same result will be displayed in a browser if you enter:
localhost:8080Now go to the
java-tutorialdirectory from the command console, and build your project again by running:Bash/Shellmvn clean installThen run:
Bash/Shellcf pushThis command deploys your Java application.
Make sure you always run
cf pushin the folder where themanifest.ymlfile is located. In this case, that’sjava-tutorial.When the staging and deployment steps are completed, the
helloworldapplication should be successfully started and its details displayed in the command console.Now open a browser window and enter the generated URL of the
helloworldapplication (seeroutes).
For example: https://helloworld-noway-panda.cfapps.eu20.hana.ondemand.com
RESULT
Your Java application is successfully deployed and running on the SAP BTP, Cloud Foundry environment. A Hello World! message is displayed in the browser.
Authentication in the SAP BTP, Cloud Foundry environment is provided by the Authorization and Trust Management (XSUAA) service. In this example, OAuth 2.0 is used as the authentication mechanism. The simplest way to add authentication is to use the Node.js @sap/approuter package. To do that, a separate Node.js micro-service will be created, acting as an entry point for the application.
In the
java-tutorialfolder, create anxs-security.jsonfile for your application with the following content:JSON{ "xsappname" : "helloworld", "tenant-mode" : "dedicated", "oauth2-configuration": { "redirect-uris": [ "https://*.cfapps.eu20.hana.ondemand.com/**" ] } }NOTE: Replace
eu20with the technical key of your actual SAP BTP region.Create an
xsuaaservice instance namedjavauaawith planapplication. To do that, run:Bash/Shellcf create-service xsuaa application javauaa -c xs-security.jsonAdd the
javauaaservice inmanifest.ymlso the file looks like this:YAML--- applications: - name: helloworld random-route: true path: ./target/java-tutorial-0.0.1-SNAPSHOT.jar memory: 1024M buildpacks: - sap_java_buildpack_jakarta env: TARGET_RUNTIME: tomcat JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jdk.SAPMachineJDK']" JBP_CONFIG_SAP_MACHINE_JDK : "{ version: 21.+ }" services: - javauaaThe
javauaaservice instance will be bound to thehelloworldapplication during deployment.Now you have to create a microservice (the application router). To do that, in the
java-tutorialfolder create a subfolderweb.IMPORTANT: Make sure you don’t have another application with the name
webin your space! If you do, use a different name and adjust the rest of the tutorial according to it.In the
webfolder, create a subfolderresources. This folder will provide the business application’s static resources.In the
resourcesfolder, create anindex.htmlfile with the following content:HTML<html> <head> <title>Java Tutorial</title> </head> <body> <h1>Java Tutorial</h1> <a href="/helloworld/">My Java Application</a> </body> </html>This will be the start page of the
helloworldapplication.In the
webdirectory, run:Bash/Shellnpm initPress Enter on every step. This process will walk you through creating a
package.jsonfile in thewebfolder.Now you need to create a directory
web/node_modules/@sapand install anapprouterpackage in it. To do that, in thewebdirectory run:Bash/Shellnpm install @sap/approuter --saveIn the
webfolder, open thepackage.jsonfile and replace the scripts section with the following:JSON"scripts": { "start": "node node_modules/@sap/approuter/approuter.js" },Now you need to add the
webapplication to your project and bind the XSUAA service instance (javauaa) to it. To do that, insert the following content at the end of yourmanifest.ymlfile.YAML- name: web random-route: true path: web memory: 1024M env: destinations: > [ { "name":"helloworld", "url":"https://helloworld-noway-panda.cfapps.eu20.hana.ondemand.com/", "forwardAuthToken": true } ] services: - javauaaNOTE: For the
urlvalue, enter your actual generated URL for thehelloworldapplication.In the
webfolder, create anxs-app.jsonfile with the following content:JSON{ "routes": [ { "source": "^/helloworld/(.*)$", "target": "$1", "destination": "helloworld" } ] }With this configuration, the incoming request is forwarded to the
helloworldapplication, configured as a destination. By default, every route requires OAuth authentication, so the requests to this path will require an authenticated user.Open your
pom.xmlfile and replace the entire<dependencies>block with the following:XML<dependencies> <!-- Spring Boot starter packages --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cloud-connectors</artifactId> <version>2.2.13.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring and XSUAA Security --> <dependency> <groupId>com.sap.cloud.security.xsuaa</groupId> <artifactId>xsuaa-spring-boot-starter</artifactId> <version>3.5.0</version> </dependency> <!-- dependencies for test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>Now go to the
java-tutorialdirectory and run:Bash/Shellmvn clean installThen run:
Bash/Shellcf pushThis command will update the
helloworldapplication and deploy thewebapplication.What’s going on?
As of this point of the tutorial, the URL of the
webapplication will be requested instead of thehelloworldURL. It will then forward the requests to thehelloworldapplication.When the staging and deployment steps are completed, the
webapplication should be successfully started and its details displayed in the command console.Open a new browser tab or window, and enter the generated URL of the
webapplication.For example:
https://web-thankfully-fox.cfapps.eu20.hana.ondemand.comEnter the credentials for your SAP BTP user and choose the default identity provider.
RESULT
A simple page with title
Java Tutorialis displayed. When you click theMy Java Applicationlink, the output of yourhelloworldapplication is displayed.Check that the
helloworldapplication is still directly accessible. To do that, refresh its previously loaded URL in a web browser.
Authorization in the SAP BTP, Cloud Foundry environment is also provided by the Authorization and Trust Management (XSUAA) service. In the previous example, the @sap/approuter package was added to provide a central entry point for the business application and to enable authentication. Now to extend the example, authorization will be added.
Navigate to
...\java_tutorialand and from its context menu, chooseNew Java File>Class.Enter
WebSecurityConfig.javaand press theENTERkey. The new class appears in the project navigation.Replace its default content with the following code:
Javapackage com.example.java_tutorial; import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration; import com.sap.cloud.security.xsuaa.token.TokenAuthenticationConverter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.convert.converter.Converter; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.web.SecurityFilterChain; @Configuration public class WebSecurityConfig { @Autowired XsuaaServiceConfiguration xsuaaServiceConfiguration; @SuppressWarnings({ "removal" }) @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .sessionManagement() // session is created by approuter .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() // demand specific scopes depending on intended request .authorizeRequests() .requestMatchers("/**").authenticated() .anyRequest().denyAll() // deny anything not configured above .and() .oauth2ResourceServer().jwt() .jwtAuthenticationConverter(getJwtAuthoritiesConverter()); return http.build(); } /** * Customizes how GrantedAuthority are derived from a Jwt * * @returns jwt converter */ Converter<Jwt, AbstractAuthenticationToken> getJwtAuthoritiesConverter() { TokenAuthenticationConverter converter = new TokenAuthenticationConverter(xsuaaServiceConfiguration); converter.setLocalScopeAsAuthorities(true); return converter; } }In the same way, create another Java class, named
NotAuthorizedException.java, and replace its default content with the following code:Javapackage com.example.java_tutorial; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @SuppressWarnings("serial") @ResponseStatus(HttpStatus.FORBIDDEN) public class NotAuthorizedException extends RuntimeException { public NotAuthorizedException(String message) { super(message); } }Open the
MainController.javafile and replace its content with the following:Javapackage com.example.java_tutorial; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.security.core.annotation.AuthenticationPrincipal; import com.sap.cloud.security.xsuaa.token.Token; @RestController @RequestMapping(path = "") public class MainController { @GetMapping(path = "") public ResponseEntity<String> readAll(@AuthenticationPrincipal Token token) { if (!token.getAuthorities().contains(new SimpleGrantedAuthority("Display"))) { throw new NotAuthorizedException("This operation requires \"Display\" scope"); } return new ResponseEntity<String>("Hello World!", HttpStatus.OK); } }To introduce an application role, open the
xs-security.jsonin thejava-tutorialfolder, and add the necessary scopeDisplayand role templateViewer, as follows:JSON{ "xsappname" : "helloworld", "tenant-mode" : "dedicated", "scopes": [ { "name": "$XSAPPNAME.Display", "description": "Display content" } ], "role-templates": [ { "name": "Viewer", "description": "View content", "scope-references": [ "$XSAPPNAME.Display" ] } ], "oauth2-configuration": { "redirect-uris": [ "https://*.cfapps.eu20.hana.ondemand.com/**" ] } }Update the XSUAA service. To do that, in the
java-tutorialdirectory run:Bash/Shellcf update-service javauaa -c xs-security.jsonBuild your project again, by running:
Bash/Shellmvn clean installFinally, run:
Bash/Shellcf push helloworldThis command will redeploy only the
helloworldapplication. No changes have been made inwebso no need to redeploy it.Try to access
helloworldagain (in a browser) in both ways โ directly, and through thewebapplication router.
RESULT
If you try to access it directly, a
401 Unauthorizedresponse is displayed due to lack of authorization token (expected behavior).If you try to access it through the app router, it results in a
403 Forbiddenresponse due to missing permissions. To get these permissions, you need to create a role collection containing the roleViewerand assign this role to your user. You can do this only from the SAP BTP cockpit.
Open the SAP BTP cockpit and go to your subaccount.
From the left-side menu, navigate to
Security>Role Collections.Create a new role collection. For example,
MyJavaAppRC.Click this role collection and then choose
Edit.In the
Rolestab, click theRole Namefield.Type Viewer. From the displayed results, select the
Viewerrole that corresponds to yourhelloworld!xxxapplication. ChooseAdd.Now go to the
Userstab, and in theIDfield, enter your e-mail. Then enter the same e-mail in theE-Mailfield.Save your changes.
Your role collection is assigned to your user and contains the role you need to view the content of your application.
Now you need to apply these changes to the
webapplication by building and redeploying it again. To do that, go back to the command line, and in thejava-tutorialdirectory, run:Bash/Shellmvn clean installAnd finally, run:
Bash/Shellcf push web
RESULT
When you try to access again the helloworld application through the app router, it will successfully display the Hello World! message.
Tip: For the new result to take effect immediately, you might need to clear the cache of your browser. Or just open the
webapplication URL in a private/incognito browser tab.
Resources
Discussion
Share feedback on this tutorial or join the conversation in SAP Community.