spec/saml/sso.cfm
2025-06-02 16:16:51 +03:00

150 lines
6.7 KiB
Plaintext

<cfinclude template="app_saml_config.cfm"/>
<!---<cfinclude template="saml.cfm"/>--->
<cfset ksFile = CreateObject("Java", "java.io.File").init(request.SAML.KEYSTORE_FILE_NAME) />
<cfset ksInputStream = CreateObject("Java", "java.io.FileInputStream").init(ksFile) />
<cfset keystore = CreateObject("Java" , "java.security.KeyStore").getInstance("JKS") />
<cfset keystore.load(ksInputStream, request.SAML.KEYSTORE_PASS.toCharArray()) />
<cfset certificate = keystore.getCertificate(request.SAML.CERTIFICATE_ALIAS) />
<cfset privateKey = keystore.getKey(request.SAML.CERTIFICATE_ALIAS, request.SAML.KEY_PASS.toCharArray()) />
<cfset signingCertString = binaryEncode(certificate.getEncoded(),"base64") />
<cfset encryptionCertString = signingCertString/>
<cfparam name="SAMLResponse"/>
<cfparam name="RelayState" default=""/>
<cfset SAMLResponseStr = ToString(ToBinary(SAMLResponse))/>
<cfset SAMLResponseXml = XMLParse(SAMLResponseStr)/><!---*** catch exception--->
<cfset SAMLStatus = XMLSearch(SAMLResponseXml, "//*[name()='samlp:StatusCode']")[1].XmlAttributes.Value/><!---*** catch exception--->
<cfset err=""/>
<cfscript>
/*
On Lucee
Error "Could not initialize class org.apache.xml.security.Init" is possibly caused by incompatible slf4j(api?)
Solution: put slf4j-api-1.7.22.jar to D:\lucee\tomcat\lib
*/
Init = CreateObject("Java", "org.apache.xml.security.Init").Init().init();
/*
// more complex way to initialize xmlsec
ref = createObject("java", "org.apache.xml.security.Init");
// writeDump(ref);
// initialize if needed
if (!ref.isInitialized()) {
// find static method named "init" with no parameters
method = ref.getClass().getDeclaredMethod("init", []);
// invoke it via reflection
method.invoke(ref, javacast("null", ""));
}
*/
dataArray=XMLSearch(SAMLResponseXml, "//*[name()='EncryptedAssertion']");
try {
dataElement=dataArray[1];
DECRYPT_MODE=CreateObject( "Java", "org.apache.xml.security.encryption.XMLCipher").DECRYPT_MODE;
cipher=CreateObject( "Java", "org.apache.xml.security.encryption.XMLCipher").getInstance();
cipher.init(DECRYPT_MODE, javacast("null", ""));
cipher.setKEK(privateKey);
cipher.doFinal(dataElement.getOwnerDocument(), dataElement, true);
} catch (any e) {
err = "Ошибка авторизации. Статус запроса: " & SAMLStatus;
}
//<!---проверка подписи--->
if (NOT len(err)) {
assertionArray = XMLSearch(SAMLResponseXml, "/*[name()='samlp:Response']/*[name()='EncryptedAssertion']/*[name()='Assertion']");
try {
assertionElement = assertionArray[1];
assertionElement.setIdAttribute("ID",true); //sic!
//WriteDump(assertionElement);
Init = CreateObject("Java", "org.apache.xml.security.Init").Init().init();
SignatureConstants = CreateObject("Java", "org.apache.xml.security.utils.Constants");
SignatureSpecNS = SignatureConstants.SignatureSpecNS; //writeDump(SignatureSpecNS);
xmlSignatureClass = CreateObject("Java", "org.apache.xml.security.signature.XMLSignature");
signatureElement=SAMLResponseXml.getElementsByTagNameNS(SignatureSpecNS,"Signature").item(0);
xmlSignature = xmlSignatureClass.init(signatureElement,"");
keyInfo = xmlSignature.getKeyInfo();
X509CertificateResolverCN = "org.apache.xml.security.keys.keyresolver.implementations.X509CertificateResolver";
keyResolver = CreateObject("Java", X509CertificateResolverCN).init();
keyInfo.registerInternalKeyResolver(keyResolver);
x509cert = keyInfo.getX509Certificate();
isValid = xmlSignature.checkSignatureValue(x509cert);
} catch (any e) {
err = "Ошибка при проверке подписи. Статус запроса: " & SAMLStatus;
}
}
</cfscript>
<cfif NOT len(err)>
<cfif (isValid NEQ 0)>
<cfset NameID=XMLSearch(SAMLResponseXml, "string(/*[name()='samlp:Response']/*[name()='EncryptedAssertion']/*[name()='Assertion']/*[name()='Subject']/*[name()='NameID'])") />
<cfset SessionIndex=XMLSearch(SAMLResponseXml, "string(//*[name()='Assertion']/*[name()='AuthnStatement']/@SessionIndex)") />
<cftry>
<cfset NotOnOrAfter=XMLSearch(SAMLResponseXml, "string(//*[name()='Assertion']/*[name()='Conditions']/@NotOnOrAfter)") />
<cfset SAML_IdPCredentialsExpirationTime=ParseDateTime(NotOnOrAfter)/>
<cfcatch type="ANY">
<cfset SAML_IdPCredentialsExpirationTime=Now()/>
</cfcatch>
</cftry>
<cfquery name="qUsr" datasource="#request.DS#">
select usr_id, locked, shortname
from usr
where login=<cfqueryparam cfsqltype="cf_sql_varchar" value="#NameID#">
</cfquery>
<cfif (qUsr.RecordCount NEQ 1)>
<cfset err="Пользователь #NameID# не зарегистрирован в данной системе."/>
<cfdump var=#SAMLResponseXml#/>
<cfset QueryAddRow(qUsr, 1)/>
<cfset qUsr.usr_id=request.GUEST_USR_ID/>
</cfif>
<cfif SAML_IdPCredentialsExpirationTime LE Now()>
<cfset err="Данные аутентификации устарели (были действительны до #dateFormat(SAML_IdPCredentialsExpirationTime,'DD.MM.YYYY')# #timeFormat(SAML_IdPCredentialsExpirationTime,'HH:MM')#). Пожалуйста, авторизуйтесь заново."/>
</cfif>
<cfelse>
<cfset err="Подпись SAML-ответа недействительна."/>
</cfif>
</cfif>
<cfif len(err)>
<cfoutput><span class="err">#err#</span></cfoutput>
<cfelse>
<cflock scope="session" type="exclusive" timeout="3">
<cfparam name="session.targetScriptName" default=""/>
<cfparam name="session.targetQueryString" default=""/>
<cfset session.SAML_NameID=#NameID#/>
<cfset session.SAML_SessionIndex=#SessionIndex#/>
<cfset session.SAML_IdPCredentialsExpirationTime=#SAML_IdPCredentialsExpirationTime#/>
<cfset session.usr_id=qUsr.usr_id/>
<cfset request.usr_id=qUsr.usr_id>
</cflock>
<!--- redirect to requested url --->
<cfset strUrl="../index.cfm"/>
<!--- <cfset strUrl="req.cfm"/> --->
<cfif len(RelayState) GT 0>
<cfset strUrl="../#RelayState#"/>
<cfelseif len(session.targetScriptName) GT 0>
<cfif NOT lCase(session.targetScriptName) EQ "login.cfm">
<cfset strUrl=#session.targetScriptName#>
<cfif len(session.targetQueryString) GT 0>
<cfif Find("?", "#strUrl#", 1) GT 0>
<cfset strUrl="../#strUrl#&#urlEncodedFormat(session.targetQueryString)#"/>
<cfelse>
<cfset strUrl="../#strUrl#?#urlEncodedFormat(session.targetQueryString)#"/>
</cfif>
</cfif>
<cfset session.targetScriptName="">
<cfset session.targetQueryString="">
</cfif>
</cfif>
<!--- <cfoutput>
<br><a href="#strUrl#">Аутентификация успешна. Продолжить работу как #qUsr.shortname#</a>
<br><pre>#saml.prettyPrintXml(SAMLResponseXml)#</pre>
</cfoutput> --->
<cflocation url="#strUrl#" addtoken="no"/>
</cfif>