1919// along with XRootD. If not, see <http://www.gnu.org/licenses/>.
2020// ------------------------------------------------------------------------------
2121
22+ #include < cctype>
2223#include < cstdio>
2324#include < cstring>
2425#include < map>
2526#include < string>
27+ #include < vector>
2628
2729#include < openssl/evp.h>
2830
2931#include " XrdHttpProtocol.hh"
3032#include " XrdHttpTrace.hh"
3133#include " XrdHttpSecXtractor.hh"
32- #include " XrdOuc/XrdOucOIDC.hh"
34+ #include " XrdSec/XrdSecLoadSecurity.hh"
35+ #include " XrdSec/XrdSecInterface.hh"
36+ #include " XrdOuc/XrdOucErrInfo.hh"
3337#include " Xrd/XrdLink.hh"
3438#include " XrdCrypto/XrdCryptoX509Chain.hh"
3539#include " XrdCrypto/XrdCryptosslAux.hh"
@@ -73,6 +77,41 @@ std::string bearerTokenKey(const char *tok, int tlen)
7377 return std::string (hex, mdLen * 2 );
7478}
7579
80+ bool hasPrefix (const char *s, const char *end, const char *pfx)
81+ {
82+ while (*pfx && s < end && *s == *pfx) {++s; ++pfx;}
83+ return !*pfx;
84+ }
85+
86+ const char *stripBearerToken (const char *bTok, int &sz)
87+ {
88+ const char *sTok = bTok;
89+ sz = 0 ;
90+ if (!sTok ) return nullptr ;
91+
92+ const char *endPtr = sTok + strlen (sTok );
93+ while (sTok < endPtr && isspace (static_cast <unsigned char >(*sTok ))) ++sTok ;
94+ if (sTok >= endPtr) return nullptr ;
95+
96+ if ((endPtr - sTok ) >= 9 && hasPrefix (sTok , endPtr, " Bearer%20" )) sTok += 9 ;
97+ else if ((endPtr - sTok ) >= 7 && hasPrefix (sTok , endPtr, " Bearer " )) sTok += 7 ;
98+
99+ while (sTok < endPtr && isspace (static_cast <unsigned char >(*sTok ))) ++sTok ;
100+ if (sTok >= endPtr) return nullptr ;
101+
102+ while (endPtr > sTok && isspace (static_cast <unsigned char >(*(endPtr - 1 )))) --endPtr;
103+ sz = static_cast <int >(endPtr - sTok );
104+ return (sz > 0 ? sTok : nullptr );
105+ }
106+
107+ void copyEntityAttrs (XrdSecEntity &dst, const XrdSecEntity &src)
108+ {
109+ for (const auto &key : src.eaAPI ->Keys ())
110+ {std::string val;
111+ if (src.eaAPI ->Get (key, val)) dst.eaAPI ->Add (key, val, true );
112+ }
113+ }
114+
76115bool extractBearerToken (const XrdHttpReq &req, std::string &token)
77116{
78117 const std::string &cgi = req.hdr2cgistr ;
@@ -129,6 +168,19 @@ bool XrdHttpProtocol::InitSecurity() {
129168 secxtractor->Init (sslctx, XrdHttpTrace.What );
130169 }
131170
171+ // Load the security framework when HTTP bearer OIDC is enabled.
172+ //
173+ if (oidcHttpMode && !CIA )
174+ {if (!oidcConfigFN)
175+ {eDest.Say (" Error: http.oidc requires a configuration file path" );
176+ return false ;
177+ }
178+ if (!(CIA = XrdSecLoadSecService (&eDest, oidcConfigFN)))
179+ {eDest.Say (" Error loading security framework for http.oidc" );
180+ return false ;
181+ }
182+ }
183+
132184// All done
133185//
134186 return true ;
@@ -144,7 +196,7 @@ XrdHttpProtocol::HandleOidcAuthentication()
144196#undef TRACELINK
145197#define TRACELINK Link
146198
147- if (!oidcHttpMode || !XrdOucOIDC::IsConfigured () ) return 0 ;
199+ if (!oidcHttpMode || !CIA ) return 0 ;
148200
149201 // Client-certificate identity is fixed for the TLS connection.
150202 if (SecEntity.name && strncmp (SecEntity.prot , " oidc" , 4 ) != 0 ) return 0 ;
@@ -160,7 +212,7 @@ XrdHttpProtocol::HandleOidcAuthentication()
160212 }
161213
162214 int tlen = 0 ;
163- const char *tok = XrdOucOIDC::StripToken (bearer.c_str (), tlen);
215+ const char *tok = stripBearerToken (bearer.c_str (), tlen);
164216 if (!tok || tlen <= 0 )
165217 {TRACEI (REQ , " OIDC bearer token malformed." );
166218 SendSimpleResp (401 , nullptr , nullptr , " Authentication failed" , 0 , false );
@@ -176,19 +228,44 @@ XrdHttpProtocol::HandleOidcAuthentication()
176228
177229 if (!oidcBearerTokKey.empty () && tokKey == oidcBearerTokKey) return 0 ;
178230
179- std::string tokStr (tok, static_cast <size_t >(tlen));
180- std::string identity, emsg;
181- std::map<std::string, std::string> entityAttrs;
182- if (!XrdOucOIDC::ValidateToken (tokStr.c_str (), identity, emsg, nullptr ,
183- &entityAttrs))
184- {TRACEI (REQ , " OIDC token validation failed: " << emsg);
231+ const int bsz = 5 + tlen + 1 ;
232+ std::vector<char > credBuf (static_cast <size_t >(bsz));
233+ strcpy (credBuf.data (), " oidc" );
234+ memcpy (credBuf.data () + 5 , tok, static_cast <size_t >(tlen));
235+ credBuf[static_cast <size_t >(5 + tlen)] = ' \0 ' ;
236+
237+ XrdSecCredentials cred;
238+ cred.buffer = credBuf.data ();
239+ cred.size = bsz;
240+
241+ XrdOucErrInfo eMsg;
242+ XrdSecProtocol *authProt = CIA ->getProtocol (Link->Host (), *(Link->AddrInfo ()),
243+ &cred, eMsg);
244+ if (!authProt)
245+ {int ec = 0 ;
246+ const char *et = eMsg.getErrText (ec);
247+ TRACEI (REQ , " OIDC protocol unavailable: " << (et && *et ? et : " unknown" ));
248+ SendSimpleResp (401 , nullptr , nullptr , " Authentication failed" , 0 , false );
249+ return 1 ;
250+ }
251+
252+ XrdSecParameters *parm = nullptr ;
253+ const int rc = authProt->Authenticate (&cred, &parm, &eMsg);
254+ if (parm) delete parm;
255+
256+ if (rc != 0 || !CIA ->PostProcess (authProt->Entity , eMsg))
257+ {int ec = 0 ;
258+ const char *et = eMsg.getErrText (ec);
259+ TRACEI (REQ , " OIDC token validation failed: " << (et && *et ? et : " unknown" ));
260+ authProt->Delete ();
185261 SendSimpleResp (401 , nullptr , nullptr , " Authentication failed" , 0 , false );
186262 return 1 ;
187263 }
188264
189265 if (!oidcBearerTokKey.empty () || Bridge)
190266 {if (Bridge && !Bridge->Disc ())
191267 {TRACEI (REQ , " OIDC token changed but bridge is busy." );
268+ authProt->Delete ();
192269 SendSimpleResp (503 , nullptr , nullptr , " Authentication busy" , 0 , false );
193270 return 1 ;
194271 }
@@ -200,10 +277,11 @@ XrdHttpProtocol::HandleOidcAuthentication()
200277 }
201278
202279 if (SecEntity.name ) free (SecEntity.name );
203- SecEntity.name = strdup (identity.c_str ());
204- strncpy (SecEntity.prot , " oidc" , sizeof (SecEntity.prot ));
205- for (const auto &attr : entityAttrs)
206- SecEntity.eaAPI ->Add (attr.first , attr.second , true );
280+ SecEntity.name = authProt->Entity .name ? strdup (authProt->Entity .name ) : nullptr ;
281+ strncpy (SecEntity.prot , authProt->Entity .prot , sizeof (SecEntity.prot ));
282+ copyEntityAttrs (SecEntity, authProt->Entity );
283+ authProt->Delete ();
284+
207285 oidcBearerTokKey = tokKey;
208286 TRACEI (REQ , " OIDC authenticated as: " << SecEntity.name );
209287 return 0 ;
0 commit comments