PartnerSystemUserService now available as REST endpoint

We are pleased to announce the SystemUser flow now has a RESTful endpoint to exchange a SystemUser token for a SystemUser SOTicket credential.

The prototype to get an SOTicket requires the same parameters as the SOAP endpoint:

  1. A signed representation of your system user token. See how to sign a system token.
  2. An application secret, also referred to as client_secret.
  3. A context identifier, which is the customer tenant ID (Cust12345).
  4. The desired token type, JWT or SAML. We recommend using only JWT as SAML support will eventually fade.
@signed_Token=YOUR_SIGNED_TOKEN
@client_Secret=YOUR_CLIENT_SECRET
@context_Identifier=YOUR_CUSTOMER_ID
@return_Token_Type=JWT|SAML

POST https://sod|qaonline|online.superoffice.com/Login/api/PartnerSystemUser/Authenticate
Content-Type: application/json
Accept: application/json

{
    "SignedSystemToken": "{{signed_Token}}",
    "ApplicationToken": "{{client_secret}}",
    "ContextIdentifier": "{{context_Identifier}}",
    "ReturnTokenType": "{{return_Token_Type}}"
}

This API should only be consumed from a server-side services. Never put sensitive information like your client_secret or private key in a javascript client (or any scripting environment) where it is exposed and vunerable.

Remember to always validate the response to ensure it hasn't been compromised enroute to your application.

Hope this help make it easier to adopt the system user flow for non-SOAP/WCF-friendly applications!

 

 

RE: PartnerSystemUserService now available as REST endpoint

Hi Tony, I'm currently working on a new framework we will use for some new generation SuperOffice apps from InfoBridge. It will be non-WCF indeed by using the AspNet.Security.OAuth.SuperOffice & SuperOffice.WebApi packages, so far that looks promising.

This PartnerSystemUserService was missing so it's a welcome addition, but I'm wondering if some helper methods for this will be included in the SuperOffice.WebApi package? Or is that out of scope? I know it's still pre-release, but to move away from WCF we cannot ignore it.

Av: Carlo Pompen 20. apr 2021

RE: PartnerSystemUserService now available as REST endpoint

The latest SuperOffice.WebApi packages contains a SystemUserClient, see https://github.com/SuperOffice/SuperOffice.WebApi-Samples#system-user

I think that is what you are looking for?

Av: David Hollegien 20. apr 2021

RE: PartnerSystemUserService now available as REST endpoint

Thanks David, I did read that before and looks suitable, so there's a bit of confusion what to use when. I should find out by trying it I guess ;)

Av: Carlo Pompen 20. apr 2021

RE: PartnerSystemUserService now available as REST endpoint

Hi Tony,

 

The page that explains how to validate the response tells us to use SuperIdTokenHandler which is available in the SuperOffice.Crm.Online.Core NuGet package.

If I reference this package in a .Net Core 3.1 application, I get this warning:

Package 'SuperOffice.Crm.Online.Core 4.0.7275.1215' was restored using '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, .NETFramework,Version=v4.8' instead of the project target framework '.NETCoreApp,Version=v3.1'. This package may not be fully compatible with your project.

If I try to use the SuperIdTokenHandler class, I get this runtime error:

FileNotFoundException: Could not load file or assembly 'System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. The system cannot find the file specified.

No surprise since System.IdentityModel belongs to .NET Framework.

 

What is the correct way to validate JWT tokens in non-SOAP/WCF-friendly applications?

Av: Véronique Borel 20. apr 2021

RE: PartnerSystemUserService now available as REST endpoint

This is great news! Posting the SOAP-envelope for authenticating the systemuser was a little 'funky' to get starter with, and this new REST-option is much easier to work with for new developers :)

Veronique: I believe the SuperOffice.Crm.Online.Core is made for .net framework, not .net CORE (i remember i was puzzled with the name of the package earlier myself). If you want to create a project on .net core i suggest you take a look at the SuperOffice.WebApi that David posted earlier in this thread. 

Regarding the validation of the returned token, depending on your requirements you could use this to validate the token: 
Override certificate resolver | SuperOffice Community 
The personally prefer this way of doing it. 


//Eivind

Av: Eivind Johan Fasting 20. apr 2021

RE: PartnerSystemUserService now available as REST endpoint

Hi Eivind,

It's exactly my point, the SuperOffice.Crm.Online.Core package is not meant for .Net Core, and as you say the WepApi package is better suited for .Net Core, in which case we wouldn't use this new endpoint.

Which means that the page Tony points to to explain how to validate the token is not exactly relevant. The page you point to yourself also references the same package so it's not a solution either.

SuperOffice.Crm.Online.Core is meant for WCF-friendly applications (as it uses WCF services itself). This REST endpoint is meant for non-WCF-friendly applications. How do we validate the token returned by this endpoint without referencing this package?

Av: Véronique Borel 21. apr 2021

RE: PartnerSystemUserService now available as REST endpoint

Hi!

I have to admit I did struggle [in my mind] as to whether I should include a link to the Validate token page, and not just mention that you should validate the token without providing a solution how. I think I will just edit the post and do away with the link to that page.

In reference to SuperOffice.Online.Core. R&D has taken steps to convert those libraries to .net standard, and it won't be long before the nuget packages get updated. Balancing resources and priorities is hard.

Let's please take a step back to gain some perspective. Like David pointed out, the SuperOffice.WebApi library (.NET Standard 2.0 - for both .NET Core and .NET Framework) already contains and implements a SystemUserClient that does the fetching and validation for you.  So with that in mind, one could say that the new endpoint is available for non-.NET libraries, or those who wish to code their own SystemUser client.

In reference to how to perform validation, I suppose I could write an article that explains how to perform JWT validation. There are dozens on the interwebs, but even after all this time I still struggle with determining where to draw the teaching line between general application development and SuperOffice APIs development? How far down the rabbit hole should I go? 

On second thought, that's a little narrow as it just addressed JWT validation and not SAML validation. Hmmm... We are advocating people not use SAML anymore, so there is that... I would rather lead you in the right direction, in accordance with our roadmap, rather than provide a means to an end that we do not want to continue to support long-term.

I have contributed to the open-source project AspNet.Security.OAuth.Providers  project does demonstrate how to perform JWT validation, but perhaps a more explicit walk-through would be more appropriate. I'll add that to the backlog.

I do just want to help make it easier to work with the API's, so I am sorry for any confusion. 

Av: Tony Yates 21. apr 2021

RE: PartnerSystemUserService now available as REST endpoint

Tony: Great news that the nuget packages will be upgraded to support .net standard :)

Veronique: Validating the token is something you can do without any of the nuget-packages from SuperOffice. 
I actually tested this earlier today to verify it works. Here is how i ended up validating the token

 private static TokenValidation ValidateJwtToken(AuthResponse authResponse, string publicKeyPath)
        {
            var tokenHandler = new JwtSecurityTokenHandler();

            X509Certificate2 cert = new X509Certificate2(publicKeyPath);
            SecurityKey key = new X509SecurityKey(cert);

            TokenValidation tokenValidation = new TokenValidation();

            try
            {
                tokenHandler.ValidateToken(authResponse.Token, new TokenValidationParameters
                {
                    IssuerSigningKey = key,
                    ValidateIssuer = false,
                    ValidateAudience = false
                }, out SecurityToken validatedToken);

                tokenValidation.JwtSecurityToken = (JwtSecurityToken)validatedToken;
            }
            catch (Exception ex)
            {
                tokenValidation.IsSuccessful = false;
                tokenValidation.ErrorMessage = ex.Message;
            }
            return tokenValidation;
        }

Note that i have created my own models for AuthResponse (which is what i get back from the REST endpoint this thread is all about) and TokenValidation (which i use elsewhere for logging if this validation should fail). 

I THINK i only use System.IdentityModel.Tokens.Jwt and Microsoft.IdentityModel.Tokens. 
An alternative is the code Christian posted in this thread: 
Topic | SuperOffice Community 

We are moving a little off track of this thread so if you need more examples i sugges you make a thread and more people can give their inputs on it :) 

Hope it helps, have a SUPER day!

//Eivind




Av: Eivind Johan Fasting 21. apr 2021

RE: PartnerSystemUserService now available as REST endpoint

Thank you both!

With Tony's answer we have an example how to validate the token the OIDC way, which doesn't require installing public certificates, while Eivind's example is useful for apps that don't use OIDC.

It's definitely helpful to have both these scenarios covered here :)

Av: Véronique Borel 22. apr 2021

RE: PartnerSystemUserService now available as REST endpoint

Hi Tony, the signed systemusertoken, which includes a timestamp, does it have a timelimit on how long it is usable?

Av: Frode Lillerud 7. maj 2021

RE: PartnerSystemUserService now available as REST endpoint

System user token is still valid for life of the app authorization against a tenant.

Av: Margrethe Romnes 7. maj 2021

RE: PartnerSystemUserService now available as REST endpoint

Hi Margrethe, thanks, but I was thinking about the "Signed SystemUserToken".

The signing can be done using this node.js/javascript code, and uses the three elements above (two private and one public), to create the signed system user token.

import moment from 'moment';
import crypto from 'crypto';

var RSA_PRIVATE_KEY = `
-----BEGIN RSA PRIVATE KEY-----
MIICWAIBAAKBgM/RT4I+j0v+1WXdf2B5ZXBOMfn80F7pkSgcjj+vVacHvTv0RkQM
REDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTED
REDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTED
REDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTED
REDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTED
REDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTED
REDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTED
REDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTED
REDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTED
REDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTED
REDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTEDREDACTED
dCHPVSNmAmmZrC4PuDS31+bmGU3yehNWelOfjA==
-----END RSA PRIVATE KEY-----
`

const SYSTEM_TOKEN = 'Frodes Demo Custom Application-REDACTED'

const utcTimestamp = moment.utc().format('YYYYMMDDHHmm');
const data = `${SYSTEM_TOKEN}.${utcTimestamp}`;

let sign = crypto.createSign('SHA256');
sign.update(data);
sign.end();

sign = sign.sign(RSA_PRIVATE_KEY, 'base64');
const signedToken = `${data}.${sign}`

console.log(signedToken)
Av: Frode Lillerud 7. maj 2021

RE: PartnerSystemUserService now available as REST endpoint

Hi Frode,

The Ticket claim value, encapsulated in the returned token, behaves exactly like a normal user Ticket credentials and should last about 6 hours, and does have a sliding expiration - extended upon each use. 

That said, the use of a system user ticket should typically be reserved for period background/channel operations, and the frequency of use really should set the tone when a new ticket is obtained. 

More frequent operations should cache the ticket as long as possible and not obtain a new one within the 6 hour window. Operations performed 4 times a day, or less, can safely get a new Ticket during the beginning of each operation. 

We do not want to see 5, 10, 20, 30 requests for a new ticket within any one hour period. That's unnecessary.

Hope this helps!

Av: Tony Yates 7. maj 2021

RE: PartnerSystemUserService now available as REST endpoint

Hi Tony, thanks for replying. However, it's still not quite answering this specific question, I'm afraid 😄

Earlier today I created a SignedSystemUserToken, and used it when making a call to the new /Login/api/PartnerSystemUser/Authenticate endpoint, and got a successful response back with the JWT token (which contains the Ticket Claim you mention). Now, a few hours later, I tried using the same SignedSystemUserToken again, and it gives 403 Forbidden. So my question is sort of answered. The SignedSystemUserToken is very short lived. More testing indicates it is only valid for a few minutes.

I'm mainly asking just to make sure I understand how all of this works - with the testing done today I now know that the signing of the SystemUserToken needs to be done often. Meaning the private RSA PEM key must be available to the application making the REST calls.

To summarize, here my understanding thus far of the entire process. My question was primarily to figure out if signing the SystemUserToken needed to be done once or many times. Conclusion is many times.

This is my attempt at structuring information into a cheatsheet.

Av: Frode Lillerud 7. maj 2021

RE: PartnerSystemUserService now available as REST endpoint

Further experimentation shows that the datetime used when signing SystemUserToken must be within 15 minutes of the time of the server. It is important that UTC time is used, not local time.

Av: Frode Lillerud 7. maj 2021

RE: PartnerSystemUserService now available as REST endpoint

Hi Frode,

Yes, that is correct. The maximum time drift of the time stamp used when submitting a signed SystemUserToken is 15 minutes.

System User Token.YYYYMMDDHHMM.mwhpYcNBfFqEaL0uLkCwXB99sM/Wo7DOnhjRwsmwNAd2EmBM1z+Co=
The timestamp is expected to be in the format "yyyyMMddHHmm" => 202101012301 and in UTC.  
 
Best regards!
 
 
Av: Tony Yates 14. jun 2021