), DE( "https://" ), DE( "http://" ) ) & cgi.http_host & reReplace( getDirectoryFromPath( arguments.template ), "([^\\/]+[\\/]){#local.requestDepth#}$", "", "one" ) ) /> var requestData = GetHttpRequestData(); var headers = requestData.headers; //var authorizationHeader = server.system.environment?.AUTHORIZATION; if (structKeyExists(headers,"Authorization")) { request.auth_header = headers.Authorization; } else { //request.auth_header = createObject("java", "java.lang.System").getEnv("AUTHORIZATION"); request.auth_header = server.system.environment?.AUTHORIZATION; //так короче if (isNull(request.auth_header)){ /*for local debug we can inject long-living token into environment*/ structDelete(request,"auth_header"); } else { request.auth_header = "Bearer #request.auth_header#"; } } // if (structKeyExists(headers,"authorization")) { // аутентификация для клиента ЛК if (structKeyExists(request,"auth_header")) { // аутентификация для клиента ЛК var authorizationHeader = request.auth_header; if (authorizationHeader.startsWith("Bearer ")) { var bearerToken = Mid(authorizationHeader, 8); //writeDump(bearerToken); //var token=toString(binaryDecode(bearerToken, "base64")); //writeDump(token); //jwt = new lib.jwt(this.client_secret); //lock scope="application" type="readonly" timeout="1" { // var token_data = (jwt.decode(token, application.idpCertificate,"RS256")); //} var result=""; //try { var iamService = new http(method = "GET", charset = "utf-8", url = #this.iamServiceUrl#, timeout="5"); iamService.addParam(type = "HEADER", name = "Accept", value = "application/json"); iamService.addParam(type = "HEADER", name = "Authorization", value = "#authorizationHeader#"); //passthrough //writedump(this.iamServiceUrl);abort; var resp = iamService.send(); //if (resp.status_code NEQ 200) throw("IDP response not OK"); //writedump(resp);abort; var prefix = resp.getPrefix(); if (prefix.status_code NEQ 200) { //writedump(this.iamServiceUrl); //writedump(resp); var iamStatusCode = (isValid("integer", prefix.status_code)) ? val(prefix.status_code) : 500; throw(message="IAM error", detail="URL: #this.iamServiceUrl# Status Code: #prefix.status_code#"); //abort; //throw("IDP response not OK"); } result = prefix.filecontent; var idpUserData=deserializeJson(result); request.auth.wz=idpUserData.userInfo.ClientId; //writeDump(idpUserData); request.auth.login = idpUserData.userInfo.login; //request.usrUid=idpUserData.userInfo.contactId;//userId; //GUID! //writedump(idpUserData);abort; //} catch (e) { /*if (fileExists("#GetDirectoryFromPath(GetCurrentTemplatePath())#/etc/local-debug")) { //true for local debug without IDP, etc/* does not go to repository var result='{"accounts":[{"login":"","type":"telegram"}],"avatar":["d2d2b7ac-50af-432b-b7c4-f7d6561e288a"],"company":"ООО «НУБЕС»","companyId":"8ec70ac0-546d-42a7-8cff-339c8fb51a23","contactId":"983967a3-58c2-4cdd-84a5-8b427ccfac82","email":"smishchuk@nubes.ru","externalUser":false,"fio":{"fullName":"Мищук Сергей ","name":"Сергей","secondName":"","surname":"Мищук"},"groupIds":["94bf5be7-52f4-5c13-87c3-513786934685","ab12b6b8-0265-4683-a5c2-5e1a74a55216","aff008c3-7443-50f6-86e1-ecff3cd3b04d","d6000da0-c9aa-55eb-9882-f118b432730b","d89a33dc-3177-5854-9580-f7f860a5ab7c","ddfe2555-9ef4-42cb-9a2b-7f24e61e7747","df12926f-ecb8-5479-857f-6d291464baad","fda5c295-230a-5025-9797-b8b4e99e08aa","2be9b4b6-94d1-59f9-a649-cab228d82169","64fe6f5c-a91b-5fea-a7ca-d9823701ebd4"],"integration":{"serviceId":""},"login":"smishchuk@nubes.ru","mobilePhone":[],"position":"","userId":"d72530e1-66a4-412f-a046-38153c4e5405"}';} */ //writedump(resp); //return representationOf( {"exception"=e} ); //rethrow(e); //} } } else { //точно мы так не словим дедлок ВПР lock scope="session" type="readonly" timeout="3" { if (structKeyExists(session, "auth")) { request.auth = structCopy(session.auth); } } if (structKeyExists(request, "auth") AND Now() < request.auth.exp) { if (dateDiff("s", request.auth.iat, Now()) > request.auth.refresh_expires_in/1.5 AND CGI.REQUEST_METHOD EQ "GET") { // доля времени, после которой происходит рефреш, прибита гвоздями // По всей видимости, рефреш будет ломать обращения POSТ // В связи с чем предлагается дождаться GET // Приклеивать query_string как-то не пришлось, браузер сам справляется // refresh var idp = new lib.oauth2(this.client_id, this.client_secret, this.auth_endpoint, this.access_token_endpoint, this.redirect_uri); var resp = idp.refreshAccessTokenRequest(request.auth.refresh_token); lock scope="application" type="readonly" timeout="1" { idpCertificate = application.idpCertificate; } var auth = parseIdpresponse(resp, idpCertificate, this.client_secret); //все эти сложности из-за опасений насчет многопоточности и блокировок lock scope="session" type="exclusive" timeout="1" { session.auth = auth; } request.auth = auth; writeDump(auth); } } else { // сессии SSO нет // или токен протух request.auth_state = createGUID().toString(); lock scope="session" type="exclusive" timeout="1" { structDelete(session, "auth"); // зачистили сессию от данных SSO session.auth_state = request.auth_state; } var idp = new lib.oauth2(this.client_id, this.client_secret, this.auth_endpoint, this.access_token_endpoint, this.redirect_uri); /* часто появляется ошибка: после неудачного запроса к IDP в адресной строке браузера остается все, с чем его редиректил IDP, а повторный запрос с этим контентом уже не работает. Получаем 400 Bad Request - может быть, KeyCloak так защищается от циклических редиректов Не очень понятно, как предотвратить повторный запрос (можно, конечно, использовать сессию, но странно) */ //writeOutput(getTickCount()-request.startTickCount); if(structKeyExists(url, "code")) { //обрабатываем редирект от IDP *** наличие поля code в URL введет нас в заблуждение, try { //writeOutput("idp.makeAccessTokenRequest"); //writeOutput(getTickCount()-request.startTickCount); var resp = idp.makeAccessTokenRequest(url.code); lock scope="application" type="readonly" timeout="1" { idpCertificate = application.idpCertificate; } var auth = parseIdpresponse(resp, idpCertificate, this.client_secret); //все эти сложности из-за опасений насчет многопоточности и блокировок lock scope="session" type="exclusive" timeout="1" { session.auth = auth; } //request.auth = auth; location(this.redirect_uri, false); } catch (e) {echo('
****************** #e.message# : #e.detail# **************');} } else { //отправляем браузер к IDP var strURL =idp.buildRedirectToAuthURL({"scope":'openid profile email',"state":request.auth_state,"allow_signup":false}); echo('self-made Auth link (idp) #strURL#

'); location(strUrl,false); } } } //request.logout_url = ""; if (structKeyExists(request, "auth") AND structKeyExists(request.auth, "id_token")) { request.logout_url = "#this.logout_endpoint#?id_token_hint=#request.auth.id_token#&post_logout_redirect_uri=#this.redirect_uri#?logout"; // внимание, здесь подразумевается, что redirect_uri не содержит query_string // после возвращения от IDP нам нужно будет зачистить сессию SSO, сделаем это по слову logout } //request.auth.wz='WZ01348'; //******************* //request.auth.wz='WZ01005'; //******************* //request.auth.wz='WZ01653'; //******************* //request.auth.wz='WZ02319'; //******************* //request.auth.wz='WZ01762'; //******************* //writedump(request.auth);abort; //******************** //костыль if (structKeyExists(URL,"wz")) { request.auth.wz=URL.wz } //*********************
--->
select value as stand from config where name='STAND' select 1; select 2; //https://keycloak.nubes.ru/admin //https://keycloak.nubes.ru/realms/SSH_CA/account //smishchuk@mgmt.nubes.ru //https://stackoverflow.com/questions/28658735/what-are-keycloaks-oauth2-openid-connect-endpoints //http://https://keycloak.nubes.ru/realms/SSH_CA/.well-known/openid-configuration //https://keycloak.nubes.ru/realms/cloud/.well-known/openid-configuration тут ссылка //https://keycloak.nubes.ru/realms/cloud/protocol/openid-connect/certs тут серт //только надо его обрамить -----BEGIN CERTIFICATE----- private function getIdpCertificate(certUrl) { var httpService = new http(); httpService.setMethod( "get" ); httpService.setCharset( "utf-8" ); httpService.setUrl(arguments.certUrl); var result = httpService.send().getPrefix(); var status_code = result.ResponseHeader['Status_Code']; if ('200' == status_code) { var content = deserializeJson(result.FileContent); //мы подразумеваем структуру конкретно KeyCloak var key = ""; for (key in content.keys) { if ("RSA" == key.kty AND "sig" == key.use) { return "-----BEGIN CERTIFICATE-----" & key.x5c[1] & "-----END CERTIFICATE-----"; } } throw(message="RSA cetificate not found"); } else { throw (message="Cannot obtain IDP certificate, request failed", detail="Status_Code #status_code#"); } } private struct function parseIdpResponse(struct resp, string certificate, string jwt_secret) { var auth = structNew("linked"); var data = deserializeJson(arguments.resp.content); var jwt = new lib.jwt(arguments.jwt_secret); auth.expires_in = data.expires_in; auth.refresh_expires_in = data.refresh_expires_in; auth.access_token = data.access_token; auth.refresh_token = data.refresh_token; auth.id_token = data.id_token; auth.token_type = data.token_type; //idp_response_content = structCopy(data); //for debug var token_data = (jwt.decode(data.access_token, arguments.certificate,"RS256")); auth.session_state = token_data.session_state; auth.sid = token_data.sid; auth.auth_time = token_data.auth_time; auth.exp = token_data.exp; auth.iat = token_data.iat; auth.login = token_data.preferred_username; auth.wz = token_data.ClientID; auth.fullname = token_data.name; auth.groups = token_data.groups; //auth.token_data = structCopy(token_data); //for debug return (auth); } select value as stand from config where name='STAND' --->