file author tngan
*  desc import { wording , namespace , StatusCode } from './urn' ; import { BindingContext } from './entity' ; import libsaml from './libsaml' ; import utility , { get } from './utility' ; import { LogoutResponseTemplate } from './libsaml' ; const binding = wording . binding ; desc param { string } referenceTagXPath param { object } entity param { function } customTagReplacement function base64LoginRequest ( referenceTagXPath , entity , customTagReplacement ? ) { const metadata = { idp : entity . idp . entityMeta , sp : entity . sp . entityMeta } ; const spSetting = entity . sp . entitySetting ; let id = '' ; if ( metadata && metadata . idp && metadata . sp ) { const base = metadata . idp . getSingleSignOnService ( binding . post ) ; let rawSamlRequest ; if ( spSetting . loginRequestTemplate && customTagReplacement ) { const info = customTagReplacement ( spSetting . loginRequestTemplate . context ) ; id = get ( info , 'id' , null ) ; rawSamlRequest = get ( info , 'context' , null ) ; } else { const nameIDFormat = spSetting . nameIDFormat ; const selectedNameIDFormat = Array . isArray ( nameIDFormat ) ? nameIDFormat [ 0 ] : nameIDFormat ; id = spSetting . generateID ( ) ; rawSamlRequest = libsaml . replaceTagsByValue ( libsaml . defaultLoginRequestTemplate . context , { ID : id , Destination : base , Issuer : metadata . sp . getEntityID ( ) , IssueInstant : new Date ( ) . toISOString ( ) , AssertionConsumerServiceURL : metadata . sp . getAssertionConsumerService ( binding . post ) , EntityID : metadata . sp . getEntityID ( ) , AllowCreate : spSetting . allowCreate , NameIDFormat : selectedNameIDFormat } as any ) ; } if ( metadata . idp . isWantAuthnRequestsSigned ( ) ) { const { privateKey , privateKeyPass , requestSignatureAlgorithm : signatureAlgorithm , transformationAlgorithms } = spSetting ; return { id , context : libsaml . constructSAMLSignature ( { referenceTagXPath , privateKey , privateKeyPass , signatureAlgorithm , transformationAlgorithms , rawSamlMessage : rawSamlRequest , signingCert : metadata . sp . getX509Certificate ( 'signing' ) , signatureConfig : spSetting . signatureConfig || { prefix : 'ds' , location : { reference : "/*[local-name(.)='AuthnRequest']/*[local-name(.)='Issuer']" , action : 'after' } , } } ) , } ; } return { id , context : utility . base64Encode ( rawSamlRequest ) , } ; } throw new Error ( 'ERR_GENERATE_POST_LOGIN_REQUEST_MISSING_METADATA' ) ; } desc param { object } requestInfo param { object } entity param { object } user param { function } customTagReplacement param { boolean } encryptThenSign async function base64LoginResponse ( requestInfo = { } , entity , user = { } , customTagReplacement ? , encryptThenSign = false ) { const idpSetting = entity . idp . entitySetting ; const spSetting = entity . sp . entitySetting ; const id = idpSetting . generateID ( ) ; const metadata = { idp : entity . idp . entityMeta , sp : entity . sp . entityMeta , } ; const nameIDFormat = idpSetting . nameIDFormat ; const selectedNameIDFormat = Array . isArray ( nameIDFormat ) ? nameIDFormat [ 0 ] : nameIDFormat ; if ( metadata && metadata . idp && metadata . sp ) { const base = metadata . sp . getAssertionConsumerService ( binding . post ) ; let rawSamlResponse ; const nowTime = new Date ( ) ; const spEntityID = metadata . sp . getEntityID ( ) ; const fiveMinutesLaterTime = new Date ( nowTime . getTime ( ) ) ; fiveMinutesLaterTime . setMinutes ( fiveMinutesLaterTime . getMinutes ( ) + 5 ) ; const fiveMinutesLater = fiveMinutesLaterTime . toISOString ( ) ; const now = nowTime . toISOString ( ) ; const acl = metadata . sp . getAssertionConsumerService ( binding . post ) ; const tvalue = { ID : id , AssertionID : idpSetting . generateID ( ) , Destination : base , Audience : spEntityID , EntityID : spEntityID , SubjectRecipient : acl , Issuer : metadata . idp . getEntityID ( ) , IssueInstant : now , AssertionConsumerServiceURL : acl , StatusCode : StatusCode . Success , ConditionsNotBefore : now , ConditionsNotOnOrAfter : fiveMinutesLater , SubjectConfirmationDataNotOnOrAfter : fiveMinutesLater , NameIDFormat : selectedNameIDFormat , NameID : user . email || '' , InResponseTo : get ( requestInfo , 'extract.request.id' , '' ) , AuthnStatement : '' , AttributeStatement : '' , } ; if ( idpSetting . loginResponseTemplate && customTagReplacement ) { const template = customTagReplacement ( idpSetting . loginResponseTemplate . context ) ; rawSamlResponse = get ( template , 'context' , null ) ; } else { if ( requestInfo !== null ) { tvalue . InResponseTo = requestInfo . extract . request . id ; } rawSamlResponse = libsaml . replaceTagsByValue ( libsaml . defaultLoginResponseTemplate . context , tvalue ) ; } const { privateKey , privateKeyPass , requestSignatureAlgorithm : signatureAlgorithm } = idpSetting ; const config = { privateKey , privateKeyPass , signatureAlgorithm , signingCert : metadata . idp . getX509Certificate ( 'signing' ) , isBase64Output : false , } ; if ( metadata . sp . isWantAssertionsSigned ( ) ) { rawSamlResponse = libsaml . constructSAMLSignature ( { ... config , rawSamlMessage : rawSamlResponse , transformationAlgorithms : spSetting . transformationAlgorithms , referenceTagXPath : "/*[local-name(.)='Response']/*[local-name(.)='Assertion']" , signatureConfig : { prefix : 'ds' , location : { reference : "/*[local-name(.)='Response']/*[local-name(.)='Assertion']/*[local-name(.)='Issuer']" , action : 'after' } , } , } ) ; } if ( ! encryptThenSign && ( spSetting . wantMessageSigned || ! metadata . sp . isWantAssertionsSigned ( ) ) ) { rawSamlResponse = libsaml . constructSAMLSignature ( { ... config , rawSamlMessage : rawSamlResponse , isMessageSigned : true , transformationAlgorithms : spSetting . transformationAlgorithms , signatureConfig : spSetting . signatureConfig || { prefix : 'ds' , location : { reference : "/*[local-name(.)='Response']/*[local-name(.)='Issuer']" , action : 'after' } , } , } ) ; } if ( idpSetting . isAssertionEncrypted ) { const context = await libsaml . encryptAssertion ( entity . idp , entity . sp , rawSamlResponse ) ; if ( encryptThenSign ) { rawSamlResponse = utility . base64Decode ( context ) as string ; } else { return Promise . resolve ( { id , context } ) ; } } if ( encryptThenSign && ( spSetting . wantMessageSigned || ! metadata . sp . isWantAssertionsSigned ( ) ) ) { rawSamlResponse = libsaml . constructSAMLSignature ( { ... config , rawSamlMessage : rawSamlResponse , isMessageSigned : true , transformationAlgorithms : spSetting . transformationAlgorithms , signatureConfig : spSetting . signatureConfig || { prefix : 'ds' , location : { reference : "/*[local-name(.)='Response']/*[local-name(.)='Issuer']" , action : 'after' } , } , } ) ; } return Promise . resolve ( { id , context : utility . base64Encode ( rawSamlResponse ) , } ) ; } throw new Error ( 'ERR_GENERATE_POST_LOGIN_RESPONSE_MISSING_METADATA' ) ; } desc param { object } user param { string } referenceTagXPath param { object } entity param { function } customTagReplacement return { string } function base64LogoutRequest ( user , referenceTagXPath , entity , customTagReplacement ? ) { const metadata = { init : entity . init . entityMeta , target : entity . target . entityMeta } ; const initSetting = entity . init . entitySetting ; const nameIDFormat = initSetting . nameIDFormat ; const selectedNameIDFormat = Array . isArray ( nameIDFormat ) ? nameIDFormat [ 0 ] : nameIDFormat ; let id = '' ; if ( metadata && metadata . init && metadata . target ) { let rawSamlRequest ; if ( initSetting . logoutRequestTemplate && customTagReplacement ) { const template = customTagReplacement ( initSetting . logoutRequestTemplate . context ) ; id = get ( template , 'id' , null ) ; rawSamlRequest = get ( template , 'context' , null ) ; } else { id = initSetting . generateID ( ) ; const tvalue = { ID : id , Destination : metadata . target . getSingleLogoutService ( binding . post ) , Issuer : metadata . init . getEntityID ( ) , IssueInstant : new Date ( ) . toISOString ( ) , EntityID : metadata . init . getEntityID ( ) , NameIDFormat : selectedNameIDFormat , NameID : user . logoutNameID , } ; rawSamlRequest = libsaml . replaceTagsByValue ( libsaml . defaultLogoutRequestTemplate . context , tvalue ) ; } if ( entity . target . entitySetting . wantLogoutRequestSigned ) { const { privateKey , privateKeyPass , requestSignatureAlgorithm : signatureAlgorithm , transformationAlgorithms } = initSetting ; return { id , context : libsaml . constructSAMLSignature ( { referenceTagXPath , privateKey , privateKeyPass , signatureAlgorithm , transformationAlgorithms , rawSamlMessage : rawSamlRequest , signingCert : metadata . init . getX509Certificate ( 'signing' ) , signatureConfig : initSetting . signatureConfig || { prefix : 'ds' , location : { reference : "/*[local-name(.)='LogoutRequest']/*[local-name(.)='Issuer']" , action : 'after' } , } } ) , } ; } return { id , context : utility . base64Encode ( rawSamlRequest ) , } ; } throw new Error ( 'ERR_GENERATE_POST_LOGOUT_REQUEST_MISSING_METADATA' ) ; } desc param { object } requestInfo param { string } referenceTagXPath param { object } entity param { function } customTagReplacement function base64LogoutResponse ( requestInfo , entity , customTagReplacement ) { const metadata = { init : entity . init . entityMeta , target : entity . target . entityMeta , } ; let id = '' ; const initSetting = entity . init . entitySetting ; if ( metadata && metadata . init && metadata . target ) { let rawSamlResponse ; if ( initSetting . logoutResponseTemplate ) { const template = customTagReplacement ( initSetting . logoutResponseTemplate . context ) ; id = template . id ; rawSamlResponse = template . context ; } else { id = initSetting . generateID ( ) ; const tvalue = { ID : id , Destination : metadata . target . getSingleLogoutService ( binding . post ) , EntityID : metadata . init . getEntityID ( ) , Issuer : metadata . init . getEntityID ( ) , IssueInstant : new Date ( ) . toISOString ( ) , StatusCode : StatusCode . Success , InResponseTo : get ( requestInfo , 'extract.request.id' , null ) } ; rawSamlResponse = libsaml . replaceTagsByValue ( libsaml . defaultLogoutResponseTemplate . context , tvalue ) ; } if ( entity . target . entitySetting . wantLogoutResponseSigned ) { const { privateKey , privateKeyPass , requestSignatureAlgorithm : signatureAlgorithm , transformationAlgorithms } = initSetting ; return { id , context : libsaml . constructSAMLSignature ( { isMessageSigned : true , transformationAlgorithms : transformationAlgorithms , privateKey , privateKeyPass , signatureAlgorithm , rawSamlMessage : rawSamlResponse , signingCert : metadata . init . getX509Certificate ( 'signing' ) , signatureConfig : { prefix : 'ds' , location : { reference : "/*[local-name(.)='LogoutResponse']/*[local-name(.)='Issuer']" , action : 'after' } } } ) , } ; } return { id , context : utility . base64Encode ( rawSamlResponse ) , } ; } throw new Error ( 'ERR_GENERATE_POST_LOGOUT_RESPONSE_MISSING_METADATA' ) ; } const postBinding = { base64LoginRequest , base64LoginResponse , base64LogoutRequest , base64LogoutResponse , } ; export default postBinding ;