2 * shibrpc-server.cpp -- SHIBRPC Server implementation. Originally created
3 * as shibrpc-server-stubs.c; make sure that the function
4 * prototypes here match those in shibrpc.x.
6 * Created by: Derek Atkins <derek@ihtfp.com>
12 #include "shib-target.h"
13 #include "ccache-utils.h"
15 #include <log4cpp/Category.hh>
18 #ifdef HAVE_LIBDMALLOCXX
24 using namespace shibboleth;
25 using namespace shibtarget;
27 static std::string get_threadid (const char* proc)
29 static u_long counter = 0;
31 buf << "[" << counter++ << "] " << proc;
35 static log4cpp::Category& get_category (void)
37 string ctx = "shibtarget.rpc-server";
38 return log4cpp::Category::getInstance(ctx);
42 shibrpc_ping_1_svc(int *argp, int *result, struct svc_req *rqstp)
49 shibrpc_session_is_valid_1_svc(shibrpc_session_is_valid_args_1 *argp,
50 shibrpc_session_is_valid_ret_1 *result,
51 struct svc_req *rqstp)
53 log4cpp::Category& log = get_category();
54 string ctx = get_threadid("session_is_valid");
57 if (!argp || !result) {
58 log.error ("RPC Argument Error");
62 memset (result, 0, sizeof (*result));
64 log.debug ("checking: %s@%s (checkAddr=%s)",
65 argp->cookie.cookie, argp->cookie.client_addr,
66 argp->checkIPAddress ? "true" : "false");
68 // See if the cookie exists...
69 CCacheEntry *entry = g_shibTargetCCache->find(argp->cookie.cookie);
71 // If not, leave now..
73 log.debug ("Not found");
74 result->status = SHIBRPC_NO_SESSION;
75 result->error_msg = strdup("No session exists for this cookie");
79 // TEST the session...
82 // Verify the address is the same
83 if (argp->checkIPAddress) {
84 log.debug ("Checking address against %s", entry->getClientAddress());
85 if (strcmp (argp->cookie.client_addr, entry->getClientAddress())) {
86 log.debug ("IP Address mismatch");
88 throw ShibTargetException(SHIBRPC_IPADDR_MISMATCH,
89 "Your IP address does not match the address in the original authentication.");
93 // and that the session is still valid...
94 if (!entry->isSessionValid(argp->lifetime, argp->timeout)) {
95 log.debug ("Session expired");
96 throw ShibTargetException(SHIBRPC_SESSION_EXPIRED,
97 "Your session has expired. Re-authenticate.");
100 // and now try to prefetch the attributes .. this could cause an
101 // "error", which is why we call it here.
103 log.debug ("resource: %s", argp->url);
104 Resource r(argp->url);
105 entry->preFetch(r,15); // give a 15-second window for the RM
107 } catch (SAMLException &e) {
108 log.debug ("prefetch failed with a SAML Exception: %s", e.what());
111 throw ShibTargetException(SHIBRPC_SAML_EXCEPTION, os.str());
114 log.error ("prefetch caught an unknown exception");
115 throw ShibTargetException(SHIBRPC_UNKNOWN_ERROR,
116 "An unknown error occured while pre-fetching attributes.");
119 } catch (ShibTargetException &e) {
121 g_shibTargetCCache->remove (argp->cookie.cookie);
122 result->status = e.which();
123 result->error_msg = strdup(e.what());
127 // Ok, just release it.
130 // ok, we've succeeded..
131 result->status = SHIBRPC_OK;
132 result->error_msg = strdup("");
133 log.debug ("session ok");
138 shibrpc_new_session_1_svc(shibrpc_new_session_args_1 *argp,
139 shibrpc_new_session_ret_1 *result, struct svc_req *rqstp)
141 log4cpp::Category& log = get_category();
142 string ctx = get_threadid("new_session");
145 if (!argp || !result) {
146 log.error ("Invalid RPC Arguments");
150 // Initialize the result structure
151 memset (result, 0, sizeof(*result));
152 result->cookie = strdup ("");
154 log.debug ("creating session for %s", argp->client_addr);
155 log.debug ("shire location: %s", argp->shire_location);
157 XMLByte* post=reinterpret_cast<XMLByte*>(argp->saml_post);
158 auto_ptr<XMLCh> location(XMLString::transcode(argp->shire_location));
160 // Pull in the Policies
161 Iterator<const XMLCh*> policies=ShibTargetConfig::getConfig().getPolicies();
163 // And grab the Profile
164 // XXX: Create a "Global" POSTProfile instance per location...
165 log.debug ("create the POST profile (%d policies)", policies.size());
166 ShibPOSTProfile *profile =
167 ShibPOSTProfileFactory::getInstance(policies,
171 SAMLResponse* r = NULL;
172 SAMLAuthenticationStatement* auth_st = NULL;
178 // Make sure we've got a profile
180 throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,
181 "Failed to obtain the profile");
183 // Try and accept the response...
184 log.debug ("Trying to accept the post");
185 r = profile->accept(post);
187 // Make sure we got a response
189 throw ShibTargetException(SHIBRPC_RESPONSE_MISSING,
190 "Failed to accept the response.");
192 // Find the SSO Assertion
193 log.debug ("Get the SSOAssertion");
194 SAMLAssertion* ssoAssertion = profile->getSSOAssertion(*r);
196 // Check against the replay cache
197 log.debug ("check replay cache");
198 if (profile->checkReplayCache(*ssoAssertion) == false)
199 throw ShibTargetException(SHIBRPC_ASSERTION_REPLAYED,
200 "Duplicate assertion found.");
202 // Get the authentication statement we need.
203 log.debug ("get SSOStatement");
204 auth_st = profile->getSSOStatement(*ssoAssertion);
206 // Maybe verify the origin address....
207 if (argp->checkIPAddress) {
208 log.debug ("check IP Address");
210 // Verify the client address exists
211 const XMLCh* ip = auth_st->getSubjectIP();
213 throw ShibTargetException(SHIBRPC_IPADDR_MISSING,
214 "The IP Address provided by your origin site was missing.");
216 log.debug ("verify client address");
217 // Verify the client address matches authentication
218 auto_ptr<char> this_ip(XMLString::transcode(ip));
219 if (strcmp (argp->client_addr, this_ip.get()))
220 throw ShibTargetException(SHIBRPC_IPADDR_MISMATCH,
221 "The IP address provided by your origin site did not match your current address. To correct this problem you may need to bypass a local proxy server.");
224 catch (SAMLException &e) // XXX refine this handler to catch and log different profile exceptions
226 log.error ("received SAML exception: %s", e.what());
229 throw ShibTargetException (SHIBRPC_SAML_EXCEPTION, os.str());
231 catch (XMLException &e)
233 log.error ("received XML exception");
234 auto_ptr<char> msg(XMLString::transcode(e.getMessage()));
235 throw ShibTargetException (SHIBRPC_XML_EXCEPTION, msg.get());
238 catch (ShibTargetException &e)
240 log.info ("FAILED: %s", e.what());
242 result->status = e.which();
243 result->error_msg = strdup(e.what());
249 log.error ("Unknown error");
251 result->status = SHIBRPC_UNKNOWN_ERROR;
252 result->error_msg = strdup("An unknown exception occurred");
257 // It passes all our tests -- create a new session.
258 log.info ("Creating new session");
260 SAMLAuthenticationStatement* as=static_cast<SAMLAuthenticationStatement*>(auth_st->clone());
262 // Create a new cookie
264 auto_ptr<char> c(XMLString::transcode(id));
265 char *cookie = c.get();
267 // Cache this session with the cookie
268 g_shibTargetCCache->insert(cookie, as, argp->client_addr);
270 // Delete the response...
273 // And let the user know.
274 free (result->cookie);
275 result->cookie = strdup(cookie);
276 result->status = SHIBRPC_OK;
277 result->error_msg = strdup("");
279 log.debug ("new session id: %s", cookie);
284 shibrpc_get_assertions_1_svc(shibrpc_get_assertions_args_1 *argp,
285 shibrpc_get_assertions_ret_1 *result, struct svc_req *rqstp)
287 log4cpp::Category& log = get_category();
288 string ctx = get_threadid("get_assertions");
291 if (!argp || !result) {
292 log.error ("Invalid RPC arguments");
296 memset (result, 0, sizeof (*result));
298 log.debug ("get attrs for client at %s", argp->cookie.client_addr);
299 log.debug ("cookie: %s", argp->cookie.cookie);
300 log.debug ("resource: %s", argp->url);
303 CCacheEntry* entry = g_shibTargetCCache->find(argp->cookie.cookie);
305 // If it does not exist, leave now..
307 log.error ("No Session");
308 result->status = SHIBRPC_NO_SESSION;
309 result->error_msg = strdup("getattrs Internal error: no session");
313 // Validate the client address (again?)
314 if (argp->checkIPAddress &&
315 strcmp (argp->cookie.client_addr, entry->getClientAddress())) {
316 log.error ("IP Mismatch");
317 result->status = SHIBRPC_IPADDR_MISMATCH;
319 strdup("Your IP address does not match the address in the original authentication.");
325 // grab the attributes for this resource
326 Resource resource(argp->url);
327 Iterator<SAMLAssertion*> iter = entry->getAssertions(resource);
328 u_int size = iter.size();
329 result->assertions.assertions_len = size;
331 // if we have assertions...
334 // Build the response section
336 (ShibRpcXML*) malloc (size * sizeof (ShibRpcXML));
337 result->assertions.assertions_val = av;
339 // and then serialize them all...
341 while (iter.hasNext()) {
342 SAMLAssertion* as = iter.next();
345 av[i++].xml_string = strdup(os.str().c_str());
348 } catch (SAMLException& e) {
349 log.error ("received SAML exception: %s", e.what());
352 result->status = SHIBRPC_SAML_EXCEPTION;
353 result->error_msg = strdup(os.str().c_str());
361 result->status = SHIBRPC_OK;
362 result->error_msg = strdup("");
364 log.debug ("returning");
369 shibrpc_prog_1_freeresult (SVCXPRT *transp, xdrproc_t xdr_result, caddr_t result)
371 xdr_free (xdr_result, result);
374 * Insert additional freeing code here, if needed