void ExtensibleAttribute::removeValue(size_t index) { Attribute::removeValue(index); DDF vals = m_obj.first(); if (index < static_cast<size_t>(vals.integer())) vals[static_cast<unsigned long>(index)].remove().destroy(); }
XMLAttribute::XMLAttribute(DDF& in) : Attribute(in) { DDF val = in.first().first(); while (val.string()) { m_values.push_back(val.string()); val = in.first().next(); } }
DDF XMLAttribute::marshall() const { DDF ddf = Attribute::marshall(); ddf.name("XML"); DDF vlist = ddf.first(); for (vector<string>::const_iterator i=m_values.begin(); i!=m_values.end(); ++i) vlist.add(DDF(NULL).string(i->c_str())); return ddf; }
DDF DDF::getmember(const char* path) const { char name[MAX_NAME_LEN+1]; const char* path_ptr=path; DDF current; if (isstruct() && ddf_strlen(ddf_token(&path_ptr,name))>0) { current.m_handle=m_handle->value.children.first; while (current.m_handle && strcmp(current.m_handle->name,name)!=0) current.m_handle=current.m_handle->next; if (current.m_handle && ddf_strlen(path_ptr)>0) current=current.getmember(path_ptr); } return current; }
void ListenerService::receive(DDF &in, ostream& out) { if (!in.name()) throw ListenerException("Incoming message with no destination address rejected."); else if (!strcmp("ping",in.name())) { DDF outmsg=DDF(NULL).integer(in.integer() + 1); DDFJanitor jan(outmsg); out << outmsg; } Locker locker(SPConfig::getConfig().getServiceProvider()); Remoted* dest=lookup(in.name()); if (!dest) throw ListenerException("No destination registered for incoming message addressed to ($1).",params(1,in.name())); dest->receive(in, out); }
const vector<string>& ExtensibleAttribute::getSerializedValues() const { if (m_serialized.empty()) { const char* formatter = m_obj["_formatter"].string(); if (formatter) { string msg = formatter; DDF val = m_obj.first().first(); while (!val.isnull()) { static const char* legal="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890_.[]"; m_serialized.push_back(string()); string& processed = m_serialized.back(); string::size_type i=0,start=0; while (start!=string::npos && start<msg.length() && (i=msg.find("$",start))!=string::npos) { if (i>start) processed += msg.substr(start,i-start); // append everything in between start=i+1; // move start to the beginning of the token name i=msg.find_first_not_of(legal,start); // find token delimiter if (i==start) { // append a non legal character processed+=msg[start++]; continue; } string tag = msg.substr(start,(i==string::npos) ? i : i-start); if (tag == "_string" && val.string()) { processed += val.string(); start=i; } else { DDF child = val.getmember(tag.c_str()); if (child.string()) processed += child.string(); else if (child.isstruct() && child["_string"].string()) processed += child["_string"].string(); start=i; } } if (start!=string::npos && start<msg.length()) processed += msg.substr(start,i); // append rest of string val = m_obj.first().next(); } } } return Attribute::getSerializedValues(); }
pair<bool,long> AssertionConsumerService::finalizeResponse( const Application& application, const HTTPRequest& httpRequest, HTTPResponse& httpResponse, string& relayState ) const { DDF postData = recoverPostData(application, httpRequest, httpResponse, relayState.c_str()); DDFJanitor postjan(postData); recoverRelayState(application, httpRequest, httpResponse, relayState); application.limitRedirect(httpRequest, relayState.c_str()); // Now redirect to the state value. By now, it should be set to *something* usable. // First check for POST data. if (!postData.islist()) { m_log.debug("ACS returning via redirect to: %s", relayState.c_str()); return make_pair(true, httpResponse.sendRedirect(relayState.c_str())); } else { m_log.debug("ACS returning via POST to: %s", relayState.c_str()); return make_pair(true, sendPostResponse(application, httpResponse, relayState.c_str(), postData)); } }
void Application::clearAttributeHeaders(SPRequest& request) const { if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) { for (vector< pair<string,string> >::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) request.clearHeader(i->first.c_str(), i->second.c_str()); return; } m_lock->rdlock(); if (m_unsetHeaders.empty()) { // No headers yet, so we have to request them from the remote half. m_lock->unlock(); m_lock->wrlock(); if (m_unsetHeaders.empty()) { SharedLock wrlock(m_lock, false); string addr=string(getId()) + "::getHeaders::Application"; DDF out,in = DDF(addr.c_str()); DDFJanitor jin(in),jout(out); out = getServiceProvider().getListenerService()->send(in); if (out.islist()) { DDF header = out.first(); while (header.isstring()) { m_unsetHeaders.push_back(pair<string,string>(header.name(),header.string())); header = out.next(); } } } else { m_lock->unlock(); } m_lock->rdlock(); } // Now holding read lock. SharedLock unsetLock(m_lock, false); for (vector< pair<string,string> >::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) request.clearHeader(i->first.c_str(), i->second.c_str()); }
DDF& DDF::empty() { if (m_handle) { switch (m_handle->type) { case ddf_body_t::DDF_STRING: if (m_handle->value.string) free(m_handle->value.string); break; case ddf_body_t::DDF_LIST: case ddf_body_t::DDF_STRUCT: { DDF temp; while (m_handle->value.children.first) { temp.m_handle=m_handle->value.children.first; temp.destroy(); } } } m_handle->type=ddf_body_t::DDF_EMPTY; } return *this; }
void ListenerService::receive(DDF &in, ostream& out) { if (!in.name()) throw ListenerException("Incoming message with no destination address rejected."); else if (!strcmp("ping", in.name())) { DDF outmsg = DDF(nullptr).integer(in.integer() + 1); DDFJanitor jan(outmsg); out << outmsg; return; } else if (!strcmp("hash", in.name())) { #ifndef SHIBSP_LITE const char* hashAlg = in["alg"].string(); const char* data = in["data"].string(); if (!hashAlg || !*hashAlg || !data || !*data) throw ListenerException("Hash request missing algorithm or data parameters."); DDF outmsg(nullptr); DDFJanitor jan(outmsg); outmsg.string(SecurityHelper::doHash(hashAlg, data, strlen(data)).c_str()); out << outmsg; return; #else throw ListenerException("Hash algorithms unavailable in lite build of library."); #endif } // Two stage lookup, on the listener itself, and the SP interface. ServiceProvider* sp = SPConfig::getConfig().getServiceProvider(); Locker locker(sp); Remoted* dest = lookup(in.name()); if (!dest) { dest = sp->lookupListener(in.name()); if (!dest) throw ListenerException("No destination registered for incoming message addressed to ($1).", params(1,in.name())); } dest->receive(in, out); }
void DDF::dump(FILE* f, int indent) const { if (!f) f=stderr; ddf_print_indent(f,indent); if (m_handle) { switch (m_handle->type) { case ddf_body_t::DDF_EMPTY: fprintf(f,"empty"); if (m_handle->name) fprintf(f," %s",m_handle->name); break; case ddf_body_t::DDF_STRING: if (m_handle->name) fprintf(f,"char* %s = ",m_handle->name); else fprintf(f,"char* = "); if (const char* chptr=m_handle->value.string) { putc('"',f); while (*chptr) fputc(*chptr++,f); putc('"',f); } else fprintf(f,"NULL"); break; case ddf_body_t::DDF_INT: if (m_handle->name) fprintf(f,"long %s = ",m_handle->name); else fprintf(f,"long = "); fprintf(f,"%ld",m_handle->value.integer); break; case ddf_body_t::DDF_FLOAT: if (m_handle->name) fprintf(f,"double %s = ",m_handle->name); else fprintf(f,"double = "); fprintf(f,"%.15f",m_handle->value.floating); break; case ddf_body_t::DDF_STRUCT: fprintf(f,"struct "); if (m_handle->name) fprintf(f,"%s ",m_handle->name); putc('{',f); if (m_handle->value.children.count) { putc('\n',f); DDF child; child.m_handle=m_handle->value.children.first; while (child.m_handle) { child.dump(f,indent+2); child.m_handle=child.m_handle->next; } } ddf_print_indent(f,indent); putc('}',f); break; case ddf_body_t::DDF_LIST: fprintf(f,"list"); if (m_handle->name) fprintf(f," %s",m_handle->name); fprintf(f,"[%lu] {",m_handle->value.children.count); if (m_handle->value.children.count) { putc('\n',f); DDF child; child.m_handle=m_handle->value.children.first; while (child.m_handle) { child.dump(f,indent+2); child.m_handle=child.m_handle->next; } } ddf_print_indent(f,indent); putc('}',f); break; case ddf_body_t::DDF_POINTER: if (m_handle->name) fprintf(f,"void* %s = ",m_handle->name); else fprintf(f,"void* = "); if (m_handle->value.pointer) fprintf(f,"%p",m_handle->value.pointer); else fprintf(f,"NULL"); break; default: fprintf(f,"UNKNOWN -- WARNING: ILLEGAL VALUE"); } } else fprintf(f,"NULL"); fprintf(f,";\n"); }
DDF SocketListener::send(const DDF& in) { #ifdef _DEBUG NDC ndc("send"); #endif log->debug("sending message (%s)", in.name() ? in.name() : "unnamed"); // Serialize data for transmission. ostringstream os; os << in; string ostr(os.str()); // Loop on the RPC in case we lost contact the first time through #ifdef WIN32 u_long len; #else uint32_t len; #endif int retry = 1; SocketListener::ShibSocket sock; while (retry >= 0) { sock = m_socketpool->get(); int outlen = ostr.length(); len = htonl(outlen); if (send(sock,(char*)&len,sizeof(len)) != sizeof(len) || send(sock,ostr.c_str(),outlen) != outlen) { log_error(); this->close(sock); if (retry) retry--; else throw ListenerException("Failure sending remoted message ($1).", params(1,in.name())); } else { // SUCCESS. retry = -1; } } log->debug("send completed, reading response message"); // Read the message. if (recv(sock,(char*)&len,sizeof(len)) != sizeof(len)) { log->error("error reading size of output message"); this->close(sock); throw ListenerException("Failure receiving response to remoted message ($1).", params(1,in.name())); } len = ntohl(len); char buf[16384]; int size_read; stringstream is; while (len && (size_read = recv(sock, buf, sizeof(buf))) > 0) { is.write(buf, size_read); len -= size_read; } if (len) { log->error("error reading output message from socket"); this->close(sock); throw ListenerException("Failure receiving response to remoted message ($1).", params(1,in.name())); } m_socketpool->put(sock); // Unmarshall data. DDF out; is >> out; // Check for exception to unmarshall and throw, otherwise return. if (out.isstring() && out.name() && !strcmp(out.name(),"exception")) { // Reconstitute exception object. DDFJanitor jout(out); XMLToolingException* except=NULL; try { except=XMLToolingException::fromString(out.string()); log->error("remoted message returned an error: %s", except->what()); } catch (XMLToolingException& e) { log->error("caught XMLToolingException while building the XMLToolingException: %s", e.what()); log->error("XML was: %s", out.string()); throw ListenerException("Remote call failed with an unparsable exception."); } auto_ptr<XMLToolingException> wrapper(except); wrapper->raise(); } return out; }
std::string getContentType() const { DDF s = m_input["content_type"]; return s.string() ? s.string() : ""; }
std::string getHeader(const char* name) const { DDF s = m_input["headers"][name]; return s.string() ? s.string() : ""; }
std::string getRemoteUser() const { DDF s = m_input["remote_user"]; return s.string() ? s.string() : ""; }
std::string getRemoteAddr() const { DDF s = m_input["client_addr"]; return s.string() ? s.string() : ""; }
void AbstractHandler::preservePostData( const Application& application, const HTTPRequest& request, HTTPResponse& response, const char* relayState ) const { #ifdef HAVE_STRCASECMP if (strcasecmp(request.getMethod(), "POST")) return; #else if (stricmp(request.getMethod(), "POST")) return; #endif // No specs mean no save. const PropertySet* props=application.getPropertySet("Sessions"); pair<bool,const char*> mech = props->getString("postData"); if (!mech.first) { m_log.info("postData property not supplied, form data will not be preserved across SSO"); return; } DDF postData = getPostData(application, request); if (postData.isnull()) return; if (strstr(mech.second,"ss:") == mech.second) { mech.second+=3; if (!*mech.second) { postData.destroy(); throw ConfigurationException("Unsupported postData mechanism ($1).", params(1, mech.second - 3)); } string postkey; if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) { DDFJanitor postjan(postData); #ifndef SHIBSP_LITE StorageService* storage = application.getServiceProvider().getStorageService(mech.second); if (storage) { // Use a random key string rsKey; SAMLConfig::getConfig().generateRandomBytes(rsKey,20); rsKey = SAMLArtifact::toHex(rsKey); ostringstream out; out << postData; if (!storage->createString("PostData", rsKey.c_str(), out.str().c_str(), time(NULL) + 600)) throw IOException("Attempted to insert duplicate storage key."); postkey = string(mech.second-3) + ':' + rsKey; } else { m_log.error("storage-backed PostData mechanism with invalid StorageService ID (%s)", mech.second); } #endif } else if (SPConfig::getConfig().isEnabled(SPConfig::InProcess)) { DDF out,in = DDF("set::PostData").structure(); DDFJanitor jin(in),jout(out); in.addmember("id").string(mech.second); in.add(postData); out = application.getServiceProvider().getListenerService()->send(in); if (!out.isstring()) throw IOException("StorageService-backed PostData mechanism did not return a state key."); postkey = string(mech.second-3) + ':' + out.string(); } // Set a cookie with key info. pair<string,const char*> shib_cookie = getPostCookieNameProps(application, relayState); postkey += shib_cookie.second; response.setCookie(shib_cookie.first.c_str(), postkey.c_str()); } else { postData.destroy(); throw ConfigurationException("Unsupported postData mechanism ($1).", params(1,mech.second)); } }
ExtensibleAttribute::ExtensibleAttribute(DDF& in) : Attribute(in), m_obj(in.copy()) { }
int ServerThread::job() { Category& log = Category::getInstance("shibd.Listener"); bool incomingError = true; // set false once incoming message is received ostringstream sink; #ifdef WIN32 u_long len; #else uint32_t len; #endif try { // Read the message. int readlength = m_listener->recv(m_sock,(char*)&len,sizeof(len)); if (readlength == 0) { log.info("detected socket closure, shutting down worker thread"); return 1; } else if (readlength != sizeof(len)) { log.error("error reading size of input message"); return -1; } len = ntohl(len); int size_read; stringstream is; while (len && (size_read = m_listener->recv(m_sock, m_buf, sizeof(m_buf))) > 0) { is.write(m_buf, size_read); len -= size_read; } if (len) { log.error("error reading input message from socket"); return -1; } // Unmarshall the message. DDF in; DDFJanitor jin(in); is >> in; log.debug("dispatching message (%s)", in.name() ? in.name() : "unnamed"); incomingError = false; // Dispatch the message. m_listener->receive(in, sink); } catch (XMLToolingException& e) { if (incomingError) log.error("error processing incoming message: %s", e.what()); DDF out=DDF("exception").string(e.toString().c_str()); DDFJanitor jout(out); sink << out; } catch (exception& e) { if (incomingError) log.error("error processing incoming message: %s", e.what()); ListenerException ex(e.what()); DDF out=DDF("exception").string(ex.toString().c_str()); DDFJanitor jout(out); sink << out; } catch (...) { if (incomingError) log.error("unexpected error processing incoming message"); if (!m_listener->m_catchAll) throw; ListenerException ex("An unexpected error occurred while processing an incoming message."); DDF out=DDF("exception").string(ex.toString().c_str()); DDFJanitor jout(out); sink << out; } // Return whatever's available. string response(sink.str()); int outlen = response.length(); len = htonl(outlen); if (m_listener->send(m_sock,(char*)&len,sizeof(len)) != sizeof(len)) { log.error("error sending output message size"); return -1; } if (m_listener->send(m_sock,response.c_str(),outlen) != outlen) { log.error("error sending output message"); return -1; } return 0; }