Skip to content

Integrating a third party SaaS application with Imona Cloud AppStore

bahadirodevci edited this page Sep 20, 2014 · 14 revisions

Add App to AppStore: To Add an application to ImonaCloud AppStore you need to have a developer account. You can get a developer account by using the link in the bottom of this page

After completing registration and login steps, you need to click on the developer link in the left menu of the App Store

in this page you will click add button and Add app to market wizard will be opened for you to enter the information about your app like the following image:

Note:
Developer will set the client id in the previous picture using App short name filed. client id will be used later by oauth2 protocol to integrate your third party app with our AppStore.(max length of client id is 8 letters)

in the wizard you have the following steps :

1- Application Info : you will enter the client id (app short name ) ,name of your application using the required languages , sector and department of your app (can be used to filter your app in our market) , your application logo and your application banner.

2- Description : you will enter short and detail description of your app using the required languages.

3- ScreenShots : here you will add screenshots of your app and they will be displayed to the end user by our AppStore.

4- Videos : you can add some videos about your app in this section.

5- Provider : here you will enter information about your company as a developer of the app.

6- Release Notes : you can add some notes about this version of the app.

7- Payment Plan : here you can select the price which the end user will pay when he wants to use your app and you can specify if you will allow the user to use your app in trial period.

8- References : in this section you can add some of the companies that are already using your application to convince the end user to buy your app.

9- integration : if you are using our platform to developer your app you can skip this page, but for the third party apps you have to fill this page with your urls like the following examples :

These urls will be used by AppStore to call your third party App and it will be explained later in this page.

Publish App to AppStore:

In the developer page there is publish button. First select an application from the draft apps and then click on publish button. You will see the following screen:

by default the app will be published to our center AppStore even if you didn't select any of installation targets and if you select them the app will be published according to the selected targets. After publishing the app the market admin should approve the app so the end user can see it in the AppStore.

Edit App in AppStore:

In the developer page there is an edit button. First select an application from the draft apps and then click on edit button. If the app is published then the version of the app will be increased by one and this new version will be not published so you can edit the information of your app in the wizard and publish it again. If the app is platform app the new script of the app will be updated when you click the publish button.

All the code examples use Apache Oltu OAuth2 Client, which can be found at http://oltu.apache.org/

Authentication:

AppStore uses OAuth2 protocol to authenticate third party SaaS applications that want to integrate with it. Authorization code grant is used for this purpose. From this point on, we will refer to the third party SaaS application as the client, and the AppStore as the server.

Ask for authorization code:

Client first needs to obtain an authorization code from the server at this URL: https://www.imona.com/store/oauth/authorize. The following information needs to be provided while requesting an authorization code:

  • Client ID that is given to the app while adding to marketplace
  • A redirect URI which the server will send a response to

Example of this process can be seen in com.imona.samplesaas.oauth.OauthUtils.askForCode() method.

OAuthClientRequest request = OAuthClientRequest
                    .authorizationLocation(authorizationUrl)
                    .setClientId("sampleSaas")
                    .setRedirectURI(redirectUri)
                    .setResponseType("code")
                    .buildQueryMessage();

resp.sendRedirect(request.getLocationUri());

As you can see, the client provides the client ID, redirect URI and sets "code" as the response type. Then it redirects the user to the resulting URI (which means it makes a request to the URL).

Ask for token:

After the client makes a request to the authorization URL, the server responds to the redirection URL, adding the code as a query parameter to the URL. This results in a request to a URL such as https://www.sampleSaas.com/redirectUri?code=1234 being made. Now that the client has the code, it can make a request to the server's token endpoint to gather an access token, which would allow it to make authorized requests to the server.

In order to obtain the access token, a request to https://www.imona.com/store/oauth/token needs to be made along with the following information:

  • Cliend ID as in the previous step
  • Client secret which is also given to the app while adding it to marketplace
  • Redirect URI which needs to be the same as in the previous step

Example of this process can be seen in com.imona.samplesaas.oauth.OauthUtils.askForToken() method.

OAuthAuthzResponse oar = OAuthAuthzResponse.oauthCodeAuthzResponse(req);
String code = oar.getCode();

OAuthClientRequest request = OAuthClientRequest
        .tokenLocation(tokenEndpointUrl)
        .setGrantType(GrantType.AUTHORIZATION_CODE)
        .setClientId("sampleSaas")
        .setClientSecret("secret")
        .setRedirectURI(redirectUri)
        .setCode(code)
        .buildBodyMessage();

//create OAuth client that uses custom http client under the hood
URLConnectionClient httpClient = new URLConnectionClient();

Map<String, String> headers = new HashMap<String, String>();
headers.put(OAuth.HeaderType.CONTENT_TYPE, OAuth.ContentType.URL_ENCODED);
headers.put(
        "Authorization",
        String.format(
                    "Basic %s",
                        new String(Base64.encode(String.format("%s:%s", "sampleSaas",
                                "secret").getBytes("UTF-8")), "UTF-8")
        )
);

OAuthJSONAccessTokenResponse response =  httpClient.execute(request, headers, "POST", OAuthJSONAccessTokenResponse.class);
req.getSession().setAttribute("token", response.getAccessToken());

An important thing to notice in the above code piece is the part that adds a header to the request. The token endpoint requires basic authentication for the requests that are being made to it. Client ID is provided as the username, client secret as the password for basic authentication. Result of this request contains the access token, which can be stored in the user's session for later use.

Make a request with the token: Once the access token is obtained, the client can use it to access protected resources on the server. Below is an example that shows how to make a request by using the access token: (code taken from com.imona.samplesaas.oauth.makeOauthRequest())

String accessToken = (String) req.getSession().getAttribute("token");
OAuthClientRequest bearerClientRequest = new OAuthBearerClientRequest(requestUri)
        .setAccessToken(accessToken).buildQueryMessage();
OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
OAuthResourceResponse resourceResponse = oAuthClient.resource(bearerClientRequest, OAuth.HttpMethod.GET, OAuthResourceResponse.class);

Map resultMap = new Gson().fromJson(resourceResponse.getBody(), Map.class);

In this example, access token which was acquired beforehand and stored in the session is used to make the request to the protected resource.

Endpoints that need to be implemented:

A third party SaaS application needs to provide URLs for 4 endpoints to integrate with Imona Cloud AppStore:

  • Login endpoint: Called by the AppStore when a user wants to navigate to the app. Upon being called, OAuth authorization flow needs to be triggered by the client. Once the flow is completed successfully, the client app needs to check if the principal(user) is a valid user for it. If it is a valid user, the client app logs the user in with the given user name. Upon successful login, client may call the User Info Endpoint that is provided by the AppStore to gather further information about the user. Example implementation for the login endpoint can be found in com.imona.samplesaas.servlet.LoginServlet class.
  • Create subscription notification endpoint: Called by the AppStore when a user adds the app to his organization account. Needs to have a placeholder {eventId} in it. The AppStore makes a HTTP GET request to this URL, replacing {eventId} with the ID of the event that occurred(create subscription event in this case). Example implementation for this endpoint can be found in com.imona.samplesaas.servlet.CreateSubscriptionEndpoint class. Sample URL: https://www.samplesaas.com/createSubs?event={eventId}
  • Add user to app notification endpoint: Called by the AppStore when an organization admin adds a user to the app. Needs to have a placeholder {eventId} in it. The AppStore makes a HTTP GET request to this URL, replacing {eventId} with the ID of the event that occurred(add user to app event in this case). Example implementation for this endpoint can be found in com.imona.samplesaas.servlet.AddUserEndpoint class. Sample URL: https://www.samplesaas.com/addUser?event={eventId}
  • Remove user from app notification endpoint: Called by the AppStore when an organization admin removes a user from the app. Needs to have a placeholder {eventId} in it. The AppStore makes a HTTP GET request to this URL, replacing {eventId} with the ID of the event that occurred(delete user from app event in this case). Example implementation for this endpoint can be found in com.imona.samplesaas.servlet.RemoveUserEndpoint class. Sample URL: https://www.samplesaas.com/removeUser?event={eventId}

The event mechanism: As you can see above, there are three event notification endpoints that are implemented on the client side. When a subscription related event is triggered by a user on the AppStore, the corresponding event endpoint is called by the AppStore. Each call holds an eventId in it, which points to a specific subscription event that occured on the AppStore. Upon receiving an event notification in these endpoints, the client needs to make a REST call to the Event Info Endpoint of the AppStore, to receive the details of the event. Once the client gets the event details from the AppStore, it makes the necessary arrangements on its side. These may be listed as:

  • Create subscription event --> Create a new organization
  • Add user to app event --> Create a new user for the organization
  • Remove user from app event --> Remove a user for the organization

Endpoints provided by the AppStore:

There are two endpoints on AppStore that serve protected resources:

  1. User Info Endpoint: Located at https://www.imona.com/store/userinfo. Accepts HTTP GET requests, returns the currently logged in user's information as JSON. Once the client is authenticated via OAuth2, it may query the server for user's extra info. This also serves the purpose of logging the user in. It's generally called upon successful completion of the OAuth2 process. Sample response:

    {
      "user_name": "user1@example.com",
      "email": "user1@example.com",
      "organization_name": "org1"
    }
    
  2. Event Info Endpoint: Located at https://www.imona.com/store/event. Accepts HTTP GET requests, returns the details for the event with the given ID. ID for the event is passed to this endpoint in the URL such as https://www.imona.com/store/event/123456. Sample response:

    {
      "eventId": "b3b8d657-fd3c-48b2-92c1-8e051abd4403",
      "userName": "user1@example.com",
      "orgUniqueName": "org1",
      "appShortName": "appppp",
      "type": "CREATE_SUBSCRIPTION"
    }
    

Type of the event may be one of CREATE_SUBSCRIPTION, ADD_USER_TO_APP and REMOVE_USER_FROM_APP.

l

Clone this wiki locally