Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#27057 EDocument Connector for Tietoevry #27233 #27626

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 55 additions & 0 deletions Apps/W1/EDocumentConnectors/Tietoevry/app/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"id": "3b3c094c-ae7f-43f2-9246-22111b688d2e",
"name": "E-Document Connector - Tietoevry",
"publisher": "Microsoft",
"brief": "E-Document Connector - Tietoevry",
"description": "E-Document Connector - Tietoevry",
"version": "26.0.0.0",
"privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009",
"EULA": "https://go.microsoft.com/fwlink/?linkid=2009120",
"help": "https://go.microsoft.com/fwlink/?linkid=2204541",
"url": "https://go.microsoft.com/fwlink/?LinkId=724011",
"logo": "ExtensionLogo.png",
"contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2206603",
"dependencies": [
{
"id": "e1d97edc-c239-46b4-8d84-6368bdf67c8b",
"name": "E-Document Core",
"publisher": "Microsoft",
"version": "26.0.27172.0"
},
{
"id": "d852a468-263e-49e5-bfda-f09e33342b89",
"name": "E-Documents Connector with External Endpoints",
"publisher": "Microsoft",
"version": "26.0.27172.0"
}
],
"internalsVisibleTo": [
{
"id": "985549ff-145a-4b5c-acd1-db6d425f6cbc",
"name": "E-Document Connector - Tietoevry Tests",
"publisher": "Microsoft"
}
],
"screenshots": [

],
"platform": "26.0.0.0",
"idRanges": [
{
"from": 6390,
"to": 6399
}
],
"resourceExposurePolicy": {
"allowDebugging": true,
"allowDownloadingSource": true,
"includeSourceInSymbolFile": true
},
"application": "26.0.0.0",
"target": "OnPrem",
"features": [
"TranslationFile"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------
namespace Microsoft.EServices.EDocumentConnector.Tietoevry;

using System.Security.Authentication;
codeunit 6394 "Authenticator"
{
Access = Internal;
Permissions = tabledata "OAuth 2.0 Setup" = im,
tabledata "Connection Setup" = rim;

procedure CreateConnectionSetupRecord()
var
ConnectionSetup: Record "Connection Setup";
begin
if not ConnectionSetup.Get() then begin
ConnectionSetup."Authentication URL" := this.AuthURLTxt;
ConnectionSetup."API URL" := this.APIURLTxt;
ConnectionSetup."Sandbox Authentication URL" := this.SandboxAuthURLTxt;
ConnectionSetup."Sandbox API URL" := this.SandboxAPIURLTxt;
ConnectionSetup."Send Mode" := ConnectionSetup."Send Mode"::Test; //Sandbox
ConnectionSetup.Insert();
end;
end;

procedure SetClientId(var ClientIdKey: Guid; ClientID: SecretText)
begin
this.SetIsolatedStorageValue(ClientIdKey, ClientID, DataScope::Company);
end;

procedure SetClientSecret(var ClienSecretKey: Guid; ClientSecret: SecretText)
begin
this.SetIsolatedStorageValue(ClienSecretKey, ClientSecret, DataScope::Company);
end;

procedure GetAccessToken() Token: SecretText
var
ConnectionSetup: Record "Connection Setup";
Requests: Codeunit Requests;
ExpiresIn: Integer;
ClientId, ClientSecret, TokenTxt, Response : SecretText;
TokenKey: Guid;
begin
ConnectionSetup.Get();

// Reuse token if it lives longer than 1 min in future
if (ConnectionSetup."Token Expiry" > CurrentDateTime() + 60 * 1000) and (not IsNullGuid(ConnectionSetup."Token - Key")) then
if this.GetTokenValue(ConnectionSetup."Token - Key", Token, DataScope::Company) then
exit;

if not this.GetTokenValue(ConnectionSetup."Client ID - Key", ClientId, DataScope::Company) then
Error(this.TietoevryClientIdErr, ConnectionSetup.TableCaption);

if not this.GetTokenValue(ConnectionSetup."Client Secret - Key", ClientSecret, DataScope::Company) then
Error(this.TietoevryClientSecretErr, ConnectionSetup.TableCaption);

Requests.Init();
Requests.CreateAuthenticateRequest(ClientId, ClientSecret);
this.ExecuteResponse(Requests, Response);
if not this.ParseResponse(Response, TokenTxt, ExpiresIn) then
Error(this.TietoevryParseTokenErr);

// Save token for reuse
this.SetIsolatedStorageValue(TokenKey, TokenTxt, DataScope::Company);
// Read again as we want fresh record to modify
ConnectionSetup.Get();
ConnectionSetup."Token - Key" := TokenKey;
ConnectionSetup."Token Expiry" := CurrentDateTime() + ExpiresIn * 1000;
ConnectionSetup.Modify();
Commit();
exit(TokenTxt);
end;

[NonDebuggable]
local procedure ExecuteResponse(var Request: Codeunit Requests; var Response: SecretText)
var
HttpExecutor: Codeunit "Http Executor";
begin
Response := HttpExecutor.ExecuteHttpRequest(Request);
end;

[NonDebuggable]
[TryFunction]
local procedure ParseResponse(Response: SecretText; var Token: SecretText; var ExpiresIn: Integer)
var
ResponseJson: JsonObject;
TokenJson, ExpiryJson : JsonToken;
begin
ResponseJson.ReadFrom(Response.Unwrap());
ResponseJson.Get('access_token', TokenJson);
Token := TokenJson.AsValue().AsText();
ResponseJson.Get('expires_in', ExpiryJson);
ExpiresIn := ExpiryJson.AsValue().AsInteger();
end;

procedure IsClientCredsSet(var ClientId: Text; var ClientSecret: Text): Boolean
var
ConnectionSetup: Record "Connection Setup";
begin
ConnectionSetup.Get();

if this.HasToken(ConnectionSetup."Client ID - Key", DataScope::Company) then
ClientId := '*';
if this.HasToken(ConnectionSetup."Client Secret - Key", DataScope::Company) then
ClientSecret := '*';
end;

procedure SetIsolatedStorageValue(var ValueKey: Guid; Value: SecretText; TokenDataScope: DataScope)
begin
if IsNullGuid(ValueKey) then
ValueKey := CreateGuid();

IsolatedStorage.Set(ValueKey, Value, TokenDataScope);
end;

local procedure GetTokenValue(TokenKey: Text; var TokenValueAsSecret: SecretText; TokenDataScope: DataScope): Boolean
begin
if not this.HasToken(TokenKey, TokenDataScope) then
exit(false);

exit(IsolatedStorage.Get(TokenKey, TokenDataScope, TokenValueAsSecret));
end;

local procedure HasToken(TokenKey: Text; TokenDataScope: DataScope): Boolean
begin
exit(IsolatedStorage.Contains(TokenKey, TokenDataScope));
end;

var
AuthURLTxt: Label 'https://auth.infotorg.no/auth/realms/fms-realm/protocol/openid-connect', Locked = true;
APIURLTxt: Label 'https://accesspoint-api.dataplatfor.ms', Locked = true;
SandboxAuthURLTxt: Label 'https://auth-qa.infotorg.no/auth/realms/fms-realm/protocol/openid-connect', Locked = true;
SandboxAPIURLTxt: Label 'https://accesspoint-api.qa.dataplatfor.ms', Locked = true;
TietoevryClientIdErr: Label 'Tietoevry Client Id is not set in %1', Comment = '%1 - Client id';
TietoevryClientSecretErr: Label 'Tietoevry Client Secret is not set in %1', Comment = '%1 - Client secret';
TietoevryParseTokenErr: Label 'Failed to parse response for Tietoevry Access token request';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------
namespace Microsoft.EServices.EDocumentConnector.Tietoevry;

using Microsoft.EServices.EDocumentConnector;

table 6392 "Connection Setup"
{
fields
{
field(1; Id; Code[10])
{
DataClassification = CustomerContent;
}
field(2; "Client Id - Key"; Guid)
{
Caption = 'Client Id';
DataClassification = EndUserIdentifiableInformation;
}
field(3; "Client Secret - Key"; Guid)
{
Caption = 'Client Secret';
DataClassification = EndUserIdentifiableInformation;
}
field(4; "Authentication URL"; Text[250])
{
Caption = 'Authentication URL';
DataClassification = CustomerContent;
Editable = false;
}
field(5; "API URL"; Text[250])
{
Caption = 'API URL';
DataClassification = CustomerContent;
Editable = false;
}
field(6; "Sandbox Authentication URL"; Text[250])
{
Caption = 'Sandbox Authentication URL';
DataClassification = CustomerContent;
Editable = false;
}
field(7; "Sandbox API URL"; Text[250])
{
Caption = 'Sandbox Authentication URL';
DataClassification = CustomerContent;
Editable = false;
}
field(8; "Token - Key"; Guid)
{
Caption = 'Token';
DataClassification = CustomerContent;
}
field(9; "Token Expiry"; DateTime)
{
Caption = 'Token Expiry';
DataClassification = CustomerContent;
}
field(10; "Company Id"; Text[250])
{
Caption = 'Company ID';
DataClassification = CustomerContent;

trigger OnValidate()
var
TietoevryProcessing: Codeunit Processing;
begin
if not TietoevryProcessing.IsValidSchemeId(Rec."Company Id") then
Rec.FieldError(Rec."Company Id");
end;
}
field(13; "Send Mode"; Enum "E-Doc. Ext. Send Mode")
Roglar01 marked this conversation as resolved.
Show resolved Hide resolved
{
Caption = 'Send Mode';
DataClassification = EndUserIdentifiableInformation;
}
}

keys
{
key(Key1; Id)
{
Clustered = true;
}
}

}
Loading
Loading