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"
14 #include <log4cpp/Category.hh>
17 #ifdef HAVE_LIBDMALLOCXX
23 using namespace shibboleth;
24 using namespace shibtarget;
26 static std::string get_threadid (const char* proc)
28 static u_long counter = 0;
30 buf << "[" << counter++ << "] " << proc;
34 static log4cpp::Category& get_category (void)
36 string ctx = "shibtarget.rpc-server";
37 return log4cpp::Category::getInstance(ctx);
41 shibrpc_ping_1_svc(int *argp, int *result, struct svc_req *rqstp)
48 shibrpc_session_is_valid_1_svc(shibrpc_session_is_valid_args_1 *argp,
49 shibrpc_session_is_valid_ret_1 *result,
50 struct svc_req *rqstp)
52 log4cpp::Category& log = get_category();
53 string ctx = get_threadid("session_is_valid");
56 if (!argp || !result) {
57 log.error ("RPC Argument Error");
61 memset (result, 0, sizeof (*result));
63 log.debug ("checking: %s@%s (checkAddr=%s)",
64 argp->cookie.cookie, argp->cookie.client_addr,
65 argp->checkIPAddress ? "true" : "false");
67 // See if the cookie exists...
68 CCacheEntry *entry = g_shibTargetCCache->find(argp->cookie.cookie);
70 // If not, leave now..
72 log.debug ("Not found");
73 result->status = SHIBRPC_NO_SESSION;
74 result->error_msg = strdup("No session exists for this cookie");
78 // Verify the address is the same
79 if (argp->checkIPAddress) {
80 log.debug ("Checking address against %s", entry->getClientAddress());
81 if (strcmp (argp->cookie.client_addr, entry->getClientAddress())) {
82 log.debug ("IP Address mismatch");
83 result->status = SHIBRPC_IPADDR_MISMATCH;
85 strdup ("Your IP address does not match the address in the original authentication.");
86 g_shibTargetCCache->remove (argp->cookie.cookie);
91 // and that the session is still valid...
92 if (!entry->isSessionValid(argp->lifetime, argp->timeout)) {
93 log.debug ("Session expired");
94 result->status = SHIBRPC_SESSION_EXPIRED;
95 result->error_msg = strdup ("Your session has expired. Re-authenticate.");
96 g_shibTargetCCache->remove (argp->cookie.cookie);
100 // ok, we've succeeded..
101 result->status = SHIBRPC_OK;
102 result->error_msg = strdup("");
103 log.debug ("session ok");
108 shibrpc_new_session_1_svc(shibrpc_new_session_args_1 *argp,
109 shibrpc_new_session_ret_1 *result, struct svc_req *rqstp)
111 log4cpp::Category& log = get_category();
112 string ctx = get_threadid("new_session");
115 if (!argp || !result) {
116 log.error ("Invalid RPC Arguments");
120 // Initialize the result structure
121 memset (result, 0, sizeof(*result));
122 result->cookie = strdup ("");
124 log.debug ("creating session for %s", argp->client_addr);
125 log.debug ("shire location: %s", argp->shire_location);
127 XMLByte* post=reinterpret_cast<XMLByte*>(argp->saml_post);
128 auto_ptr<XMLCh> location(XMLString::transcode(argp->shire_location));
130 // Pull in the Policies
131 static const XMLCh* clubShib[] = {shibboleth::Constants::POLICY_CLUBSHIB};
132 ArrayIterator<const XMLCh*> policies(clubShib);
134 // And grab the Profile
135 // XXX: Create a "Global" POSTProfile instance per location...
136 log.debug ("create the POST profile (%d policies)", policies.size());
137 ShibPOSTProfile *profile =
138 ShibPOSTProfileFactory::getInstance(policies,
142 SAMLResponse* r = NULL;
143 SAMLAuthenticationStatement* auth_st = NULL;
149 // Make sure we've got a profile
151 throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,
152 "Failed to obtain the profile");
154 // Try and accept the response...
155 log.debug ("Trying to accept the post");
156 r = profile->accept(post);
158 // Make sure we got a response
160 throw ShibTargetException(SHIBRPC_RESPONSE_MISSING,
161 "Failed to accept the response.");
163 // Find the SSO Assertion
164 log.debug ("Get the SSOAssertion");
165 SAMLAssertion* ssoAssertion = profile->getSSOAssertion(*r);
167 // Check against the replay cache
168 log.debug ("check replay cache");
169 if (profile->checkReplayCache(*ssoAssertion) == false)
170 throw ShibTargetException(SHIBRPC_ASSERTION_REPLAYED,
171 "Duplicate assertion found.");
173 // Get the authentication statement we need.
174 log.debug ("get SSOStatement");
175 auth_st = profile->getSSOStatement(*ssoAssertion);
177 // Maybe verify the origin address....
178 if (argp->checkIPAddress) {
179 log.debug ("check IP Address");
181 // Verify the client address exists
182 const XMLCh* ip = auth_st->getSubjectIP();
184 throw ShibTargetException(SHIBRPC_IPADDR_MISSING,
185 "The IP Address provided by your origin site was missing.");
187 log.debug ("verify client address");
188 // Verify the client address matches authentication
189 auto_ptr<char> this_ip(XMLString::transcode(ip));
190 if (strcmp (argp->client_addr, this_ip.get()))
191 throw ShibTargetException(SHIBRPC_IPADDR_MISMATCH,
192 "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.");
195 catch (SAMLException &e) // XXX refine this handler to catch and log different profile exceptions
197 log.error ("received SAML exception: %s", e.what());
200 throw ShibTargetException (SHIBRPC_SAML_EXCEPTION, os.str());
202 catch (XMLException &e)
204 log.error ("received XML exception");
205 auto_ptr<char> msg(XMLString::transcode(e.getMessage()));
206 throw ShibTargetException (SHIBRPC_XML_EXCEPTION, msg.get());
209 catch (ShibTargetException &e)
211 log.info ("FAILED: %s", e.what());
213 result->status = e.which();
214 result->error_msg = strdup(e.what());
220 log.error ("Unknown error");
222 result->status = SHIBRPC_UNKNOWN_ERROR;
223 result->error_msg = strdup("An unknown exception occurred");
228 // It passes all our tests -- create a new session.
229 log.info ("Creating new session");
231 SAMLAuthenticationStatement* as=static_cast<SAMLAuthenticationStatement*>(auth_st->clone());
233 // Create a new cookie
235 auto_ptr<char> c(XMLString::transcode(id));
236 char *cookie = c.get();
238 // Cache this session with the cookie
239 g_shibTargetCCache->insert(cookie, as, argp->client_addr);
241 // Delete the response...
244 // And let the user know.
245 free (result->cookie);
246 result->cookie = strdup(cookie);
247 result->status = SHIBRPC_OK;
248 result->error_msg = strdup("");
250 log.debug ("new session id: %s", cookie);
255 shibrpc_get_assertions_1_svc(shibrpc_get_assertions_args_1 *argp,
256 shibrpc_get_assertions_ret_1 *result, struct svc_req *rqstp)
258 log4cpp::Category& log = get_category();
259 string ctx = get_threadid("get_assertions");
262 if (!argp || !result) {
263 log.error ("Invalid RPC arguments");
267 memset (result, 0, sizeof (*result));
269 log.debug ("get attrs for client at %s", argp->cookie.client_addr);
270 log.debug ("cookie: %s", argp->cookie.cookie);
271 log.debug ("resource: %s", argp->url);
274 CCacheEntry* entry = g_shibTargetCCache->find(argp->cookie.cookie);
276 // If it does not exist, leave now..
278 log.error ("No Session");
279 result->status = SHIBRPC_NO_SESSION;
280 result->error_msg = strdup("getattrs Internal error: no session");
284 // Validate the client address (again?)
285 if (argp->checkIPAddress &&
286 strcmp (argp->cookie.client_addr, entry->getClientAddress())) {
287 log.error ("IP Mismatch");
288 result->status = SHIBRPC_IPADDR_MISMATCH;
290 strdup("Your IP address does not match the address in the original authentication.");
295 // grab the attributes for this resource
296 Resource resource(argp->url);
297 Iterator<SAMLAssertion*> iter = entry->getAssertions(resource);
298 u_int size = iter.size();
299 result->assertions.assertions_len = size;
301 // if we have assertions...
304 // Build the response section
306 (ShibRpcXML*) malloc (size * sizeof (ShibRpcXML));
307 result->assertions.assertions_val = av;
309 // and then serialize them all...
311 while (iter.hasNext()) {
312 SAMLAssertion* as = iter.next();
315 av[i++].xml_string = strdup(os.str().c_str());
318 } catch (SAMLException& e) {
319 log.error ("received SAML exception: %s", e.what());
322 result->status = SHIBRPC_SAML_EXCEPTION;
323 result->error_msg = strdup(os.str().c_str());
328 result->status = SHIBRPC_OK;
329 result->error_msg = strdup("");
331 log.debug ("returning");
336 shibrpc_prog_1_freeresult (SVCXPRT *transp, xdrproc_t xdr_result, caddr_t result)
338 xdr_free (xdr_result, result);
341 * Insert additional freeing code here, if needed