Komma igång med integrationsvy
Till Boendekalkylen finns en modul kallad "Integrationsvy". Vyns syfte är:
Att enklare kunna integrera låneprocessens användargränssnitt med Boendekalkylens användargränssnitt.
Att snabbt kunna visa uppgifter som man vill se för ett ärende i låneprocessen
Att lösa en del tekniska utmaningar:
Kunna köra Boendekalkylen cross-domain i en IFRAME som dynamiskt kan ändra storlek
Cross-domain kunna kommunicera mellan Låneprocessens användargränssnitt och Boendekalkylens användargränssnitt
Kunna starta Boendekalkylens fulla gränssnitt, redigera ett underlag och sedan tillbaka igen till låneprocessen
Detta dokument beskriver hur man kommer igång med Boendekalkylens integrationsvy i ett användargränssnitt för låneprocess. Dokumentet beskriver detta ur perspektivet att Boendekalkylen körs som moln-lösning hos Vitec och därmed så beskrivs inte själva konfigurationen av Boendekalkylen som behöver göras då detta utförs av Vitec vid moln-drift.
Exempel på integrationsvyn i användargränssnittet i ett låneprocess-system
Inloggning för demo skapas på begäran.
Övergripande systemskiss

Innehåll och utformning av själva integrationsvyn
Detta styrs av boendekalkylens konfigurationsfil som vid moln-drift hanteras av Vitec. Beställningar av justeringar görs på "verksamhetsnivå" till Vitec.
API - integrationsvy
API-funktion | Parametrar | Beskrivning |
---|---|---|
window.cpxBoendeKalkyl.InitieraVy |
Alternativ:
| Visar integrationsvyn för angiven kalkyl på önskat ställe på HTML-sidan. När man öppnar/stänger boendekalkylens gränssnitt och när man sparar ett ändrat underlag så anropas callbacken och sidan som visar vyn kan då skicka case’t vidare i processen. e.Anledning = ”OEPPNAR_BOENDEKALKYLEN” e.Anledning = ”STAENGER_BOENDEKALKYLEN” e.Anledning = ”SPARAT_KALKYLEN” e.KalkylID = ID på kalkylen Om boendekalkylen är konfigurerad att tillåta ”spara som ny” så kan man få ett nytt e.KalkylID än det man ursprungligen öppnade i integrationsvyn. Callback är optional Options: Object { kalkylid: String, viewactions: boolean (visa/dölj viewactions, d.v.s. redigeraknappen) } |
window.cpxBoendeKalkyl.Login |
| Loggar in med angiven Ticket och anropar en callback när inloggninen är klar. LoginParametrar styr autentiseringen och vad man skickar med här beror på vilken typ av autentiseringsmetod som är konfigurerad. Vad en ticket ska vara beror på hur boendekalkylens autentisering är konfigurerad. Vilken autentisering som används väljer ni som kund genom beställning till Vitec. Vid drift hos Vitec är det SAML som gäller.
|
SAML
Vid SAML är det än så länge så att det är anroparen som autentiserar personen och skapar SAML-Response. Detta behövs för att det ska bli "Single Sign On". Dvs för att göra detta så behöver anroparen ha ett bibliotek som kan skapa ett SAML-Response samt ett privat certifikat för att signera med. Den publika delen av certifikatet ska skickas över till Vitec som installerar det i Boendekalkylen.
Det finns ett projekt på CodeProject som med källkod visar tydligt hur man gör en SAML-login. Performing a SAML Post with C#.
SAML Exempelkod
public
static
string GetPostSamlResponse(string recipient, string issuer, string domain, string subject, StoreLocation storeLocation, StoreName storeName, X509FindType findType, X509Certificate2 cert, string certPassword, Dictionary<string, string> attributes) {
SigningHelper.SignatureType signatureType = SigningHelper.SignatureType.Response;
ResponseType responseType =
new
ResponseType();
responseType.ID =
"_"
+ Guid.NewGuid().ToString();
responseType.Destination = recipient;
responseType.Version =
"2.0"
;
responseType.IssueInstant = DateTime.UtcNow;
responseType.Issuer =
new
NameIDType {
Value = issuer.Trim()
};
responseType.Status =
new
StatusType();
responseType.Status.StatusCode =
new
StatusCodeType();
responseType.Status.StatusCode.Value =
"urn:oasis:names:tc:SAML:2.0:status:Success"
;
XmlSerializer xmlSerializer =
new
XmlSerializer(responseType.GetType());
StringWriter stringWriter =
new
StringWriter();
XmlWriter xmlWriter = XmlWriter.Create(stringWriter,
new
XmlWriterSettings {
OmitXmlDeclaration =
true
,
Indent =
true
,
Encoding = Encoding.UTF8
});
string text = string.Empty;
AssertionType assertionType = CreateSamlAssertion(issuer.Trim(), recipient.Trim(), domain.Trim(), subject.Trim(), attributes);
responseType.Items =
new
AssertionType[] {
assertionType
};
xmlSerializer.Serialize(xmlWriter, responseType);
xmlWriter.Close();
text = stringWriter.ToString();
text = text.Replace(
"SubjectConfirmationData"
, string.Format(
"SubjectConfirmationData NotOnOrAfter=\"{0:o}\" Recipient=\"{1}\""
, DateTime.UtcNow.AddMinutes(
5.0
), recipient));
stringWriter.Close();
XmlDocument xmlDocument =
new
XmlDocument();
xmlDocument.LoadXml(text);
XmlElement newChild = SigningHelper.SignDoc(xmlDocument, cert,
"ID"
, (signatureType == SigningHelper.SignatureType.Response) ? responseType.ID : assertionType.ID);
xmlDocument.DocumentElement.InsertBefore(newChild, xmlDocument.DocumentElement.ChildNodes[
1
]);
string outerXml = xmlDocument.OuterXml;
byte
[] bytes = Encoding.UTF8.GetBytes(outerXml);
return
Convert.ToBase64String(bytes);
}
private
static
AssertionType CreateSamlAssertion(string issuer, string recipient, string domain, string subject, Dictionary<string, string> attributes) {
AssertionType assertionType =
new
AssertionType();
assertionType.ID =
"_"
+ Guid.NewGuid().ToString();
assertionType.Issuer =
new
NameIDType {
Value = issuer.Trim()
};
assertionType.Version =
"2.0"
;
assertionType.IssueInstant = DateTime.UtcNow;
ConditionsType conditionsType =
new
ConditionsType();
conditionsType.NotBefore = DateTime.UtcNow;
conditionsType.NotBeforeSpecified =
true
;
conditionsType.NotOnOrAfter = DateTime.UtcNow.AddMinutes(
5.0
);
conditionsType.NotOnOrAfterSpecified =
true
;
conditionsType.Items =
new
ConditionAbstractType[] {
new
AudienceRestrictionType {
Audience =
new
string[] {
domain.Trim()
}
}
};
NameIDType nameIDType =
new
NameIDType();
nameIDType.NameQualifier = domain.Trim();
nameIDType.Value = subject.Trim();
SubjectConfirmationType subjectConfirmationType =
new
SubjectConfirmationType();
SubjectConfirmationDataType subjectConfirmationData =
new
SubjectConfirmationDataType();
subjectConfirmationType.Method =
"urn:oasis:names:tc:SAML:2.0:cm:bearer"
;
subjectConfirmationType.SubjectConfirmationData = subjectConfirmationData;
SubjectType subjectType =
new
SubjectType();
AttributeStatementType attributeStatementType =
new
AttributeStatementType();
AuthnStatementType authnStatementType =
new
AuthnStatementType();
authnStatementType.AuthnInstant = DateTime.UtcNow;
AuthnContextType authnContextType =
new
AuthnContextType();
AuthnContextType arg_14C_0 = authnContextType;
ItemsChoiceType5[] itemsElementName =
new
ItemsChoiceType5[
1
];
arg_14C_0.ItemsElementName = itemsElementName;
authnContextType.Items =
new
object[] {
"AuthnContextClassRef"
};
authnStatementType.AuthnContext = authnContextType;
subjectType.Items =
new
object[] {
nameIDType,
subjectConfirmationType
};
assertionType.Subject = subjectType;
IPHostEntry hostEntry = Dns.GetHostEntry(Environment.MachineName);
SubjectLocalityType subjectLocalityType =
new
SubjectLocalityType();
subjectLocalityType.Address = hostEntry.AddressList[
0
].ToString();
attributeStatementType.Items =
new
AttributeType[attributes.Count];
int
num =
0
;
foreach (KeyValuePair<string, string> current in attributes) {
AttributeType attributeType =
new
AttributeType();
attributeType.Name = current.Key;
attributeType.NameFormat =
"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
;
attributeType.AttributeValue =
new
object[] {
current.Value
};
attributeStatementType.Items[num] = attributeType;
num++;
}
assertionType.Conditions = conditionsType;
assertionType.Items =
new
StatementAbstractType[] {
authnStatementType,
attributeStatementType
};
return
assertionType;
}
Möjlig vidareutveckling för SAML-inloggning
Tycker ni att detta är bökigt så kan vi vidareutveckla Integrationsvyn så att den kan hantera att användaren inte är inloggad och då visa en inloggningsruta som användaren först måste fylla i innan integrationsvyn visas, men det blir ju då ett extra steg för användaren som inte är speciellt användarvänligt.
Sedan finns ett mellanting vi skulle kunna vidareutveckla och det är att vi tillhandahåller webservice-funktioner till vår autentiserings-system "Vitec IAM" så att ni till det systemet kan anropa en webservice och skicka in användarnamn + lösenord och sedan få tillbaka en SAML Response som ni kan skicka in till integrationsvyn och till webservice-anrop ni vill göra i process-systemet. Gör ni på detta sätt så behöver ni alltså bara visa en inloggningsruta en gång och sedan kan ni återanvända SAML Response under en viss tid till alla anrop så länge som kunden är inne och kör i process-systemet.
Båda dessa vidareutvecklingar måste beställas i förväg och hanteras som anpassningsarbete på konsultbasis.
Komplett exempel för att starta Integrationsvyn med SAML-inloggning
Nedanstående exempel förutsätter att det finns en boendekalkyl installerad på context-path "j" på en websajt med host-namn "https://capitexboendekalkyl-exempel.capitex.vitec.net" samt att den är konfigurerad för SAML och integrationsvy.
URL till scriptet från Vitec vid "moln-drift" hos Vitec
"konfigurationsId" i exempelkoden nedan fås från Vitec vid "moln-drift" hos Vitec
Den ticket som syns nedan fungerar endast med ett specifikt testceritifikat och för en begränsad tid, så den ticket'en fungerar alltså inte att använda i något exempel-anrop
KalkylID 700fa55:16307059af3:-7fed i exempelkoden nedan är bara ett exempel och KalkylID är alltså en uppgift som sparas i låneprocessen tillsammans med ärendet och den måste hämtas därifrån.
<
html
>
<
body
>
<
script
src
=
"https://capitexboendekalkyl-exempel.capitex.vitec.net/j/cpxintegration.js"
></
script
>
<
div
id
=
"cpxcontainer"
/>
<
script
>
var ticket = "PFJlc3BvbnNlI…HhtbG5zOnhzaT0ia+"; //OSB! Nedkortad icke fungerande ticket…
window.cpxBoendeKalkyl.Login(
"cpxcontainer",
{konfigurationsId:'guiconf'},
ticket,
function() {
window.cpxBoendeKalkyl.InitieraVy(
"cpxcontainer",
"700fa55:16307059af3:-7fed",
function(e) {
// Här ska man informera låneprocess-systemet att kalkylen blivit uppdaterad,
// hur man gör beror på vilket process-system som används.
// I vissa system anropar man process-systemets klient-api som i sin tur anropar backend
// I vissa system anropar man själv process-systemets backend med ett "ajax/rest"-anrop
alert(e.Anledning);
});
});
</
script
>
</
body
>
</
html
>
För att ovanstående ska fungera måste boendekalkylen skicka ett OnApplicationLoaded event till integrationsvyn. Detta görs genom att i konfigurationen av boendekalkylen ha med följande custom javascript
<capitex_boendekalkyl_vy_customjs>
<![CDATA[
window.parent.postMessage({
function
:
"OnApplicationLoaded"
},
"*"
);
]]>
<capitex_boendekalkyl_vy_customjs>
Exempel för att starta Integrationsvyn utan inloggning
Om kalkylen hostas hos banken och access kontrolleras genom extern accesskontroll som hanteras av banken så startar man integrationsvyn utan login enligt nedan:
Integrationsvy utan login
<
html
>
<
body
>
<
script
src
=
"https://capitexboendekalkyl-exempel.capitex.vitec.net/j/cpxintegration.js"
></
script
>
<
div
id
=
"cpxcontainer"
/>
<
script
>
window.cpxBoendeKalkyl.InitieraVy("cpxcontainer", "700fa55:16307059af3:-7fed",
function(e) {
// Här ska man informera låneprocess-systemet att kalkylen blivit uppdaterad,
// hur man gör beror på vilket process-system som används.
// I vissa system anropar man process-systemets klient-api som i sin tur anropar backend
// I vissa system anropar man själv process-systemets backend med ett "ajax/rest"-anrop
alert(e.Anledning);
});
</
script
>
</
body
>
</
html
>
Exempel med options variabeln:
Integrationsvy utan login
<!DOCTYPE html>
<
html
lang
=
"sv"
>
<
head
>
<
meta
charset
=
"utf-8"
/>
</
head
>
<
body
>
<
script
src
=
"https://capitexboendekalkyl-exempel.capitex.vitec.net/j/cpxintegration.js"
></
script
>
<
div
id
=
"cpxcontainer4"
class
=
"capitex-application"
/>
<
script
>
var id = "" + Math.random();
document.getElementsByClassName("capitex-application")[0].id = id;
var options = {};
options.kalkylid = "5ca1de53:166afbdd26c:-7ffd";
options.viewactions = false;
window.cpxBoendeKalkyl.InitieraVy(id, options, '', function(e) {});
</
script
>
</
body
>
</
html
>