import"../node-crypto-polyfill.js";import{DOMParser as b}from"@xmldom/xmldom";import{SignedXml as B}from"xml-crypto";import F from"xpath";import{deflateSync as J,inflateSync as q}from"fflate";import{createHash as H}from"crypto";import{AuthProviderType as u,DEFAULT_TEAM_CLAIM_NAME as W}from"@redocly/config";import{AUTH_URL as K,JWT_SECRET_KEY as _}from"../constants/common.js";import{getPathPrefix as Q,withPathPrefix as X}from"@redocly/theme/core/utils";import{DEFAULT_AUTHENTICATED_TEAM as Y,REQUIRED_OIDC_SCOPES as D,ServerRoutes as P}from"../../constants/common.js";import{appendQueryParams as G}from"../../utils/url/append-query-params.js";import{logger as Z}from"../tools/notifiers/logger.js";import{AlgorithmTypes as I,JwtTokenExpired as ee}from"./jwt/types.js";import*as p from"./jwt/jwt.js";import{parseTeamClaimToArray as te,randomString as ne,randomUUID as v}from"../utils/index.js";import{arrayBufferToBase64 as ae,decodeBase64 as R,encodeBase64URL as re,urlSafeBase64 as j}from"./jwt/encode.js";import{formatSamlCertificate as oe}from"./utils/format-saml-certificate.js";function E(e){return e?.type===u.OIDC}function se(e){return e?.type===u.SAML2}async function Ee(e,t){if(E(t))return ie(e,t);if(se(t))return ce(e,t)}async function ie(e,t){const a=await V(e,t),n=new Set((t.scopes||[]).concat(D)),r=t.authorizationRequestCustomParams||{};return{type:u.OIDC,idpId:e,name:"OAuth provider",authorizationEndpoint:a.authorization_endpoint,clientId:t.clientId,responseType:"code",scope:Array.from(n).join(" "),extraParams:r,pkce:t.pkce}}function ce(e,t){return{type:u.SAML2,idpId:e,name:"SAML2 provider",ssoUrl:t.ssoUrl,issuerId:t.issuerId,entityId:t.entityId||t.issuerId}}async function Ne(e,t,a,n,r={}){const o=new Set((n.scopes||[]).concat(D));return await fetch(e,{method:"POST",body:new URLSearchParams({client_id:n.clientId,scope:Array.from(o).join(" "),code:t,redirect_uri:N(a),grant_type:"authorization_code",...n.clientSecret?{client_secret:n.clientSecret}:{},...r}).toString(),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"}}).then(s=>s.json())}function de(e,{authorizationEndpoint:t,clientId:a,responseType:n,scope:r,extraParams:o,idpId:s,pkce:i},m,A,w){if(!t||!a||!n||!r)return{loginUrl:void 0};const d=new URL(t),f=w?.redirectUriOverride??`${e}${X(P.OIDC_CALLBACK)}`,S={state:v(),idpId:s,redirectUri:f,redirectTo:m,branch:w?.branchOverride??ue(e),inviteCode:A,source:w?.sourceOverride??"portal"},h={};if(i){const l=j(ne(50)),g=j(H("sha256").update(l).digest("base64")),x="S256";d.searchParams.append("code_challenge",g),d.searchParams.append("code_challenge_method",x),h.code_verifier={value:l,options:{secure:!0,httpOnly:!0,expires:new Date(Date.now()+1e3*60*10),path:Q()||"/"}}}d.searchParams.append("client_id",a),d.searchParams.append("scope",r),d.searchParams.append("response_type",n),d.searchParams.append("redirect_uri",N(f)),d.searchParams.append("state",re(JSON.stringify(S)));for(const l in o)o[l]!==void 0&&d.searchParams.append(l,o[l]);return{loginUrl:d.toString(),cookies:h}}function Ve(e,t,a,n){const r=new URL(e);return r.searchParams.append("post_logout_redirect_uri",t),n&&r.searchParams.append("state",n),r.searchParams.append("id_token_hint",a),r.toString()}async function ze(e){const t=Math.floor(Date.now()/1e3),a=t+(e.ttlSec??600);return p.sign({type:"mcp_auth_code",client_id:e.clientId,redirect_uri:e.redirectUri,id_token:e.idToken,iat:t,exp:a},_)}async function $e(e){const{header:t,payload:a}=p.decode(e),r=Object.values(I).includes(t.alg)?t.alg:I.HS256;if(await p.verify(e,_,r),!a||typeof a!="object")throw new Error("Malformed authorization code");const o=a;if((o.typ??o.type)!=="mcp_auth_code")throw new Error("Invalid authorization code type");const i=a;if(!i.client_id||!i.redirect_uri)throw new Error("Authorization code missing required claims");if(i.exp&&Date.now()>=i.exp*1e3)throw new Error("Authorization code expired");return i}function N(e){return e.match(/^https:\/\/preview-[^\.]+--/)?"https://previewauth--"+e.split("--")[1]:e.match(/^(https:\/\/[^\.]+)--[^\.]+\.preview\./)?e.replace(/^(https:\/\/[^\.]+?)--[^\.]+\.preview\./,"$1.previewauth."):e}function ue(e){return e.match(/^(https:\/\/[^\.]+)--([^\.]+)\.preview\./)?.[2]||void 0}function le(e){return e.type===u.OIDC}function me(e){return e.type===u.SAML2}function Be(e,t,a,n){return le(e)?de(t,e,a,n):me(e)?pe(t,e,a,n):{}}function pe(e,t,a,n){const o=`<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    Version="2.0"
    ID="_${v()}"
    IssueInstant="${new Date().toISOString()}"
    AssertionConsumerServiceURL="${e}${P.SAML_CALLBACK}"
    AttributeConsumingServiceIndex="0">
    <saml:Issuer>${t.entityId}</saml:Issuer>
    <samlp:NameIDPolicy
      AllowCreate="true"
      Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/>
  </samlp:AuthnRequest>`,s=fe(o);return{loginUrl:G(t.ssoUrl,{SAMLRequest:s,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:a,inviteCode:n,source:"portal"})})}}function fe(e){return ae(J(new TextEncoder().encode(e)).buffer)}function Fe(e){const t=R(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const a=q(new Uint8Array(atob(e).split("").map(n=>n.charCodeAt(0))));return new TextDecoder().decode(a)}function Je(e){try{return JSON.parse(R(e||""))}catch{throw new Error("Invalid OAuth2 state")}}function qe(e){const t=new b().parseFromString(e,"application/xml"),n=c(t,"//*[local-name(.)='StatusCode']/@Value")[0]?.nodeValue?.endsWith("Success")||!1,o=c(t,"//*[local-name(.)='Response']/@Destination")[0]?.nodeValue||"",s=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='Issuer']/text()")[0],i=s&&s.nodeValue||void 0,m=c(t,"//*[local-name(.)='Audience']/text()")[0],A=m&&m.nodeValue||void 0,d=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='X509Certificate']/text()")[0]?.nodeValue||"",f=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/text()")[0],S=f&&f.nodeValue||"",h=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/@Format")[0],l=h&&h.nodeValue||"",g=c(t,"//*[local-name(.)='Conditions']/@NotOnOrAfter")[0],x=he(g),T={},k=c(t,"//*[local-name(.)='AttributeStatement']//*[local-name(.)='Attribute']");if(k.length)for(const C of k){const O=c(C,"./@Name")[0];if(O.nodeValue){const U=c(C,"./*[local-name(.)='AttributeValue']/text()")[0];U?.nodeValue&&(T[O.nodeValue]=U.nodeValue)}}return{uid:S,success:n,expiresAt:x,issuerId:i,entityId:A,attrs:T,cert:d,nameFormat:l,destination:o}}function he(e){const t=typeof e?.nodeValue=="string"&&L(Date.parse(e.nodeValue)),a=L(Date.now()),n=L(Date.now()+720*60*1e3);return t?t>a&&t<n?n:t:a}function L(e){return Math.floor(e/1e3)}const M={},y={jwks:{}};async function V(e,t){return M[e]||(M[e]=t.configurationUrl?await z(t.configurationUrl):t.configuration),M[e]}async function ye(e){for(const t of Object.keys(e)){const a=e[t];if(!E(a))continue;const n=await V(t,a);if(n.jwks_uri){const r=await z(n.jwks_uri);for(const o of r.keys)y.jwks[o.kid]={...o,idpId:t}}}}async function z(e){return fetch(e,{headers:{Accept:"application/json"}}).then(t=>t.json())}async function He(e){return fetch(`${K}/oidc/userinfo`,{headers:{Accept:"application/json",Authorization:`Bearer ${e}`}}).then(t=>t.status===200?t.json():void 0).catch(()=>{})}function We(e){if(!e.configurationUrl)return!1;const t=new URL(e.configurationUrl);return["localhost","127.0.0.1","blueharvest.cloud","bhstage.cloud","cloud.redocly.com","beta.redocly.com","cloud.eu.redocly.com","beta.eu.redocly.com","cba.au.redocly.com"].some(n=>we(t.hostname,n))}function we(e,t){return e===t||e.endsWith(`.${t}`)}async function Ke(e,t){const a=new b().parseFromString(e),n=c(a,"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];if(!n)throw new Error("Cannot find Signature in the SAML response");const r=oe(t),o=new B({publicCert:r});o.loadSignature(n);try{return o.checkSignature(e)}catch{return!1}}function Qe(e,t,a,n){t==="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"&&(e=a["http://schemas.microsoft.com/identity/claims/objectidentifier"]);let r;(t==="urn:oasis:names:tc:SAML:2.0:nameid-format:email"||t==="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")&&(r=e),t==="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"&&e?.match(/.+@.+/)&&(r=e);const o=a["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"],s=o?.match(/.+@.+/);return r=r||a["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]||(s?o:void 0),r=r?.toLowerCase(),{sub:e,given_name:a["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"],family_name:a["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"],name:a["http://schemas.microsoft.com/identity/claims/displayname"]||o,email:r,email_verified:!0,teams:n?te(a[n]):[]}}function $(e,t={}){return e.map(a=>t[a]||a)}async function Xe(e,t){if(!t)return{};const a=t.authorization;if(!a)return{};try{const n=p.decode(a);if(n.header.alg===I.RS256){y.jwks[n.header.kid]===void 0&&await ye(e);const m=y.jwks[n.header.kid];if(!m)return y.jwks[n.header.kid]=null,{};await p.verify(a,m,n.header.alg)}else await p.verify(a,_,n.header.alg);const r=n.payload.idpId||y.jwks[n.header.kid]?.idpId,o=e[r]||{},s=ge(o),i=Se(o);return{...n.payload,email:n.payload.email?.toLowerCase(),idpId:r,teams:Array.from(new Set([...$(n.payload.teams||[],i),..."defaultTeams"in o&&o.defaultTeams||[],...$("teamsClaimName"in o&&n.payload[s||""]||[],i),Y])),name:Ae(n.payload),isAuthenticated:!0,idpAccessToken:t.idp_access_token,federatedAccessToken:t.federated_access_token,federatedIdToken:t.federated_id_token,authCookie:a}}catch(n){n instanceof ee||Z.error("Malformed JWT token: %s",n.message)}return{}}function Ae(e){return e.name||e.given_name||e.email}function Se(e){switch(e.type){case u.SAML2:return e.teamsAttributeMap;case u.OIDC:return e.teamsClaimMap;default:return}}function ge(e){switch(e.type){case u.SAML2:return e.teamsAttributeName;case u.OIDC:return e.teamsClaimName;default:return W}}function c(e,t){return F.select(t,e)||[]}export{Be as buildLoginUrl,de as buildOidcLoginUrl,Ve as buildOidcLogoutUrl,pe as buildSAML2LoginUrl,ze as createMcpAuthorizationCode,Fe as decodeSamlResponse,fe as encodeSAML2,Qe as extractUserClaims,Ee as getAuthProviderLoginParams,ie as getOidcLoginParams,V as getOidcMetadata,He as getRedoclyTokenPayload,ce as getSaml2LoginParams,Xe as getUserParamsFromCookies,Ae as getUsernameFromPayload,E as isOidcProviderConfig,We as isRedoclySso,se as isSaml2ProviderConfig,Ne as oidcExchangeCodeForToken,Je as parseOidcState,ue as parsePreviewBranch,qe as parseSamlResponse,N as rewritePreviewAuthRedirectUri,$e as verifyMcpAuthorizationCode,Ke as verifySAMLResponse};
