/** * アクセストークンを取得します. OAuthサービスプロバイダに認証コードを送信して、 認証済みリクエストトークンを交換してアクセストークンを取得します. * * @param verifier 認証コード * @param requestToken 認証済みリクエストトークン * @param tokenSecret トークンシークレット */ public void getAccessToken(String verifier, String requestToken, String tokenSecret) { // OAuthコンシューマを作成 OAuthConsumer consumer = new OAuthConsumer(callbackUrl, consumerKey, consumerSecret, provider); // OAuthのアクセサーを作成 accessor = new OAuthAccessor(consumer); accessor.requestToken = requestToken; accessor.tokenSecret = tokenSecret; try { // アクセスコードをパラメータで渡す Map<String, Object> parameters = new HashMap<String, Object>(); parameters.put(OAuth.OAUTH_VERIFIER, verifier); // アクセストークンを取得する OAuthMessage response = client.getAccessToken(accessor, null, parameters.entrySet()); response.requireParameters(OAuth.OAUTH_TOKEN, OAuth.OAUTH_TOKEN_SECRET); System.out.println(OAuth.OAUTH_TOKEN + "(AccessToken): " + accessor.accessToken); System.out.println(OAuth.OAUTH_TOKEN_SECRET + ": " + accessor.tokenSecret); } catch (IOException e) { e.printStackTrace(); } catch (OAuthException e) { e.printStackTrace(); } catch (URISyntaxException e) { e.printStackTrace(); } }
/** * Throw an exception if the timestamp is out of range or the nonce has been validated previously. */ protected void validateTimestampAndNonce(OAuthMessage message) throws IOException, OAuthProblemException { message.requireParameters(OAuth.OAUTH_TIMESTAMP, OAuth.OAUTH_NONCE); long timestamp = Long.parseLong(message.getParameter(OAuth.OAUTH_TIMESTAMP)); long now = currentTimeMsec(); validateTimestamp(message, timestamp, now); validateNonce(message, timestamp, now); }
/** * Check that the verifier is valid for the current message * * @author Jack Hsu */ public void validateVerifier(OAuthMessage message) throws IOException, OAuthException { String consumerKey = message.getConsumerKey(); String requestToken = message.getParameter(OAuth.OAUTH_TOKEN); String key = consumerKey + ":" + requestToken; String verifier = message.getParameter(OAuth.OAUTH_VERIFIER); if (verifier == null || !verifier.equals(VERIFIERS.get(key))) { throw new OAuthProblemException(OAuth.Problems.PARAMETER_REJECTED); } else { // Remove verifier so it can't be used again VERIFIERS.remove(key); } }
@Test public void testGetTemporaryCredentialsURIQuery() throws Exception { Map<String, String> parameters = new HashMap<String, String>(); parameters.put(OAuth.OAUTH_CALLBACK, OAuthTestUtils.CALLBACK); // check all parameter transmissions for (ParameterStyle style : ParameterStyle.values()) { // for all signing methods for (String signMethod : OAuthTestUtils.SIGN_METHOD) { LOG.log( Level.INFO, "Preparing request with parameter style: {0} and signature method: {1}", new String[] {style.toString(), signMethod}); parameters.put(OAuth.OAUTH_SIGNATURE_METHOD, signMethod); parameters.put(OAuth.OAUTH_NONCE, UUID.randomUUID().toString()); parameters.put(OAuth.OAUTH_TIMESTAMP, String.valueOf(System.currentTimeMillis() / 1000)); parameters.put(OAuth.OAUTH_CONSUMER_KEY, OAuthTestUtils.CLIENT_ID); OAuthMessage message = invokeRequestToken(parameters, style, OAuthServer.PORT); // test response ok boolean isFormEncoded = OAuth.isFormEncoded(message.getBodyType()); Assert.assertTrue(isFormEncoded); List<OAuth.Parameter> responseParams = OAuthTestUtils.getResponseParams(message); String wwwHeader = message.getHeader("Authenticate"); Assert.assertNull(wwwHeader); String callbacConf = OAuthTestUtils.findOAuthParameter(responseParams, OAuth.OAUTH_CALLBACK_CONFIRMED) .getValue(); Assert.assertEquals("true", callbacConf); String oauthToken = OAuthTestUtils.findOAuthParameter(responseParams, OAuth.OAUTH_TOKEN).getKey(); Assert.assertFalse(StringUtils.isEmpty(oauthToken)); String tokenSecret = OAuthTestUtils.findOAuthParameter(responseParams, OAuth.OAUTH_TOKEN_SECRET).getKey(); Assert.assertFalse(StringUtils.isEmpty(tokenSecret)); // test wrong client id parameters.put(OAuth.OAUTH_CONSUMER_KEY, "wrong"); message = invokeRequestToken(parameters, style, OAuthServer.PORT); String response = message.getHeader("oauth_problem"); Assert.assertEquals(OAuth.Problems.CONSUMER_KEY_UNKNOWN, response); } } }
private HttpResponse makeOAuthProblemReport(String code, String text, int rc) throws IOException { if (vagueErrors) { return new HttpResponseBuilder() .setHttpStatusCode(rc) .setResponseString("some vague error") .create(); } OAuthMessage msg = new OAuthMessage(null, null, null); msg.addParameter("oauth_problem", code); msg.addParameter("oauth_problem_advice", text); return new HttpResponseBuilder() .setHttpStatusCode(rc) .addHeader("WWW-Authenticate", msg.getAuthorizationHeader("realm")) .create(); }
public static String getParameter(OAuthMessage requestMessage, String key) { try { return StringUtils.trim(requestMessage.getParameter(key)); } catch (IOException e) { return null; } }
/** Throw an exception if any SINGLE_PARAMETERS occur repeatedly. */ protected void checkSingleParameters(OAuthMessage message) throws IOException, OAuthException { // Check for repeated oauth_ parameters: boolean repeated = false; Map<String, Collection<String>> nameToValues = new HashMap<String, Collection<String>>(); for (Map.Entry<String, String> parameter : message.getParameters()) { String name = parameter.getKey(); if (SINGLE_PARAMETERS.contains(name)) { Collection<String> values = nameToValues.get(name); if (values == null) { values = new ArrayList<String>(); nameToValues.put(name, values); } else { repeated = true; } values.add(parameter.getValue()); } } if (repeated) { Collection<OAuth.Parameter> rejected = new ArrayList<OAuth.Parameter>(); for (Map.Entry<String, Collection<String>> p : nameToValues.entrySet()) { String name = p.getKey(); Collection<String> values = p.getValue(); if (values.size() > 1) { for (String value : values) { rejected.add(new OAuth.Parameter(name, value)); } } } OAuthProblemException problem = new OAuthProblemException(OAuth.Problems.PARAMETER_REJECTED); problem.setParameter(OAuth.Problems.OAUTH_PARAMETERS_REJECTED, OAuth.formEncode(rejected)); throw problem; } }
protected SecurityToken verifyMessage(OAuthMessage message) throws OAuthProblemException { OAuthEntry entry = getOAuthEntry(message); OAuthConsumer authConsumer = getConsumer(message); OAuthAccessor accessor = new OAuthAccessor(authConsumer); if (entry != null) { accessor.tokenSecret = entry.tokenSecret; accessor.accessToken = entry.token; } try { message.validateMessage(accessor, new SimpleOAuthValidator()); } catch (OAuthProblemException e) { throw e; } catch (OAuthException e) { OAuthProblemException ope = new OAuthProblemException(OAuth.Problems.SIGNATURE_INVALID); ope.setParameter(OAuth.Problems.OAUTH_PROBLEM_ADVICE, e.getMessage()); throw ope; } catch (IOException e) { OAuthProblemException ope = new OAuthProblemException(OAuth.Problems.SIGNATURE_INVALID); ope.setParameter(OAuth.Problems.OAUTH_PROBLEM_ADVICE, e.getMessage()); throw ope; } catch (URISyntaxException e) { OAuthProblemException ope = new OAuthProblemException(OAuth.Problems.SIGNATURE_INVALID); ope.setParameter(OAuth.Problems.OAUTH_PROBLEM_ADVICE, e.getMessage()); throw ope; } return getTokenFromVerifiedRequest(message, entry, authConsumer); }
public String generateVerifier(OAuthAccessor accessor, OAuthMessage message) throws IOException { String consumerKey = accessor.consumer.consumerKey; String requestToken = message.getParameter(OAuth.OAUTH_TOKEN); String key = consumerKey + ":" + requestToken; String verifier = String.format("%08d", RANDOM_NUMBER.nextInt(99999999)); VERIFIERS.put(key, verifier); return verifier; }
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { OAuthConsumer consumer = null; try { final OAuthMessage requestMessage = OAuthServlet.getMessage(request, null); requestMessage.requireParameters("consumer"); final String consumerName = requestMessage.getParameter("consumer"); consumer = CookieConsumer.getConsumer(consumerName, null); final CookieMap cookies = new CookieMap(request, response); final OAuthAccessor accessor = CookieConsumer.newAccessor(consumer, cookies); final String expectedToken = accessor.requestToken; String requestToken = requestMessage.getParameter(OAuth.OAUTH_TOKEN); if (requestToken == null || requestToken.length() <= 0) { log.warning(request.getMethod() + " " + OAuthServlet.getRequestURL(request)); requestToken = expectedToken; if (requestToken == null) { OAuthProblemException problem = new OAuthProblemException(OAuth.Problems.PARAMETER_ABSENT); problem.setParameter(OAuth.Problems.OAUTH_PARAMETERS_ABSENT, OAuth.OAUTH_TOKEN); throw problem; } } else if (!requestToken.equals(expectedToken)) { OAuthProblemException problem = new OAuthProblemException("token_rejected"); problem.setParameter("oauth_rejected_token", requestToken); problem.setParameter("oauth_expected_token", expectedToken); throw problem; } List<OAuth.Parameter> parameters = null; String verifier = requestMessage.getParameter(OAuth.OAUTH_VERIFIER); if (verifier != null) { parameters = OAuth.newList(OAuth.OAUTH_VERIFIER, verifier); } OAuthMessage result = CookieConsumer.CLIENT.getAccessToken(accessor, null, parameters); if (accessor.accessToken != null) { String returnTo = requestMessage.getParameter("returnTo"); if (returnTo == null) { returnTo = request.getContextPath(); // home page } cookies.remove(consumerName + ".requestToken"); cookies.put(consumerName + ".accessToken", accessor.accessToken); cookies.put(consumerName + ".tokenSecret", accessor.tokenSecret); throw new RedirectException(returnTo); } OAuthProblemException problem = new OAuthProblemException(OAuth.Problems.PARAMETER_ABSENT); problem.setParameter(OAuth.Problems.OAUTH_PARAMETERS_ABSENT, OAuth.OAUTH_TOKEN); problem.getParameters().putAll(result.getDump()); throw problem; } catch (Exception e) { CookieConsumer.handleException(e, request, response, consumer); } }
protected void validateVersion(OAuthMessage message) throws OAuthException, IOException { String versionString = message.getParameter(OAuth.OAUTH_VERSION); if (versionString != null) { double version = Double.parseDouble(versionString); if (version < minVersion || maxVersion < version) { OAuthProblemException problem = new OAuthProblemException(OAuth.Problems.VERSION_REJECTED); problem.setParameter( OAuth.Problems.OAUTH_ACCEPTABLE_VERSIONS, minVersion + "-" + maxVersion); throw problem; } } }
// Hand out a request token if the consumer key and secret are valid private void createRequestToken( HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException, OAuthException, URISyntaxException { OAuthMessage requestMessage = OAuthServlet.getMessage(servletRequest, null); String consumerKey = requestMessage.getConsumerKey(); if (consumerKey == null) { OAuthProblemException e = new OAuthProblemException(OAuth.Problems.PARAMETER_ABSENT); e.setParameter(OAuth.Problems.OAUTH_PARAMETERS_ABSENT, OAuth.OAUTH_CONSUMER_KEY); throw e; } OAuthConsumer consumer = dataStore.getConsumer(consumerKey); if (consumer == null) throw new OAuthProblemException(OAuth.Problems.CONSUMER_KEY_UNKNOWN); OAuthAccessor accessor = new OAuthAccessor(consumer); VALIDATOR.validateMessage(requestMessage, accessor); String callback = null; if (enableSignedCallbacks) { callback = requestMessage.getParameter(OAuth.OAUTH_CALLBACK); } if (callback == null && !enableOAuth10) { OAuthProblemException e = new OAuthProblemException(OAuth.Problems.PARAMETER_ABSENT); e.setParameter(OAuth.Problems.OAUTH_PARAMETERS_ABSENT, OAuth.OAUTH_CALLBACK); throw e; } // generate request_token and secret OAuthEntry entry = dataStore.generateRequestToken( consumerKey, requestMessage.getParameter(OAuth.OAUTH_VERSION), callback); List<Parameter> responseParams = OAuth.newList(OAuth.OAUTH_TOKEN, entry.token, OAuth.OAUTH_TOKEN_SECRET, entry.tokenSecret); if (callback != null) { responseParams.add(new Parameter(OAuthConstants.OAUTH_CALLBACK_CONFIRMED, "true")); } sendResponse(servletResponse, responseParams); }
/** * Throw an exception if the nonce has been validated previously. * * @return the earliest point in time at which a call to releaseGarbage will actually release some * garbage, or null to indicate there's nothing currently stored that will become garbage in * future. */ protected Date validateNonce(OAuthMessage message, long timestamp, long currentTimeMsec) throws IOException, OAuthProblemException { UsedNonce nonce = new UsedNonce( timestamp, message.getParameter(OAuth.OAUTH_NONCE), message.getConsumerKey(), message.getToken()); /* * The OAuth standard requires the token to be omitted from the stored * nonce. But I include it, to harmonize with a Consumer that generates * nonces using several independent computers, each with its own token. */ boolean valid = false; synchronized (usedNonces) { valid = usedNonces.add(nonce); } if (!valid) { throw new OAuthProblemException(OAuth.Problems.NONCE_USED); } return removeOldNonces(currentTimeMsec); }
public SecurityToken getSecurityTokenFromRequest(HttpServletRequest request) throws InvalidAuthenticationException { OAuthMessage message = OAuthServlet.getMessage(request, null); if (StringUtils.isEmpty(getParameter(message, OAuth.OAUTH_SIGNATURE))) { // Is not an oauth request return null; } String bodyHash = getParameter(message, OAuthConstants.OAUTH_BODY_HASH); if (!StringUtils.isEmpty(bodyHash)) { verifyBodyHash(request, bodyHash); } try { return verifyMessage(message); } catch (OAuthProblemException oauthException) { // Legacy body signing is intended for backwards compatability with opensocial clients // that assumed they could use the raw request body as a pseudo query param to get // body signing. This assumption was born out of the limitations of the OAuth 1.0 spec which // states that request bodies are only signed if they are form-encoded. This lead many clients // to force a content type of application/x-www-form-urlencoded for xml/json bodies and then // hope that receiver decoding of the body didnt have encoding issues. This didn't work out // to well so now these clients are required to specify the correct content type. This code // lets clients which sign using the old technique to work if they specify the correct content // type. This support is deprecated and should be removed later. if (allowLegacyBodySigning && (StringUtils.isEmpty(request.getContentType()) || !request.getContentType().contains(OAuth.FORM_ENCODED))) { try { message.addParameter(readBodyString(request), ""); return verifyMessage(message); } catch (OAuthProblemException ioe) { // ignore, let original exception be thrown } catch (IOException e) { // also ignore; } } throw new InvalidAuthenticationException("OAuth Authentication Failure", oauthException); } }
/** * Construct an HTTP request from this OAuth message. * * @param style where to put the OAuth parameters, within the HTTP request */ public static HttpMessage newRequest(OAuthMessage from, ParameterStyle style) throws IOException { final boolean isPost = OAuthMessage.POST.equalsIgnoreCase(from.method); InputStream body = from.getBodyAsStream(); if (style == ParameterStyle.BODY && !(isPost && body == null)) { style = ParameterStyle.QUERY_STRING; } String url = from.URL; final List<Map.Entry<String, String>> headers = new ArrayList<Map.Entry<String, String>>(from.getHeaders()); switch (style) { case QUERY_STRING: url = OAuth.addParameters(url, from.getParameters()); break; case BODY: { byte[] form = OAuth.formEncode(from.getParameters()).getBytes(from.getBodyEncoding()); headers.add(new OAuth.Parameter(CONTENT_TYPE, OAuth.FORM_ENCODED)); headers.add(new OAuth.Parameter(CONTENT_LENGTH, form.length + "")); body = new ByteArrayInputStream(form); break; } case AUTHORIZATION_HEADER: headers.add(new OAuth.Parameter("Authorization", from.getAuthorizationHeader(null))); // Find the non-OAuth parameters: List<Map.Entry<String, String>> others = from.getParameters(); if (others != null && !others.isEmpty()) { others = new ArrayList<Map.Entry<String, String>>(others); for (Iterator<Map.Entry<String, String>> p = others.iterator(); p.hasNext(); ) { if (p.next().getKey().startsWith("oauth_")) { p.remove(); } } // Place the non-OAuth parameters elsewhere in the request: if (isPost && body == null) { byte[] form = OAuth.formEncode(others).getBytes(from.getBodyEncoding()); headers.add(new OAuth.Parameter(CONTENT_TYPE, OAuth.FORM_ENCODED)); headers.add(new OAuth.Parameter(CONTENT_LENGTH, form.length + "")); body = new ByteArrayInputStream(form); } else { url = OAuth.addParameters(url, others); } } break; } HttpMessage httpRequest = new HttpMessage(from.method, new URL(url), body); httpRequest.headers.addAll(headers); return httpRequest; }
private OAuthEntry getValidatedEntry(OAuthMessage requestMessage) throws IOException, ServletException, OAuthException, URISyntaxException { OAuthEntry entry = dataStore.getEntry(requestMessage.getToken()); if (entry == null) throw new OAuthProblemException(OAuth.Problems.TOKEN_REJECTED); if (entry.type != OAuthEntry.Type.REQUEST) throw new OAuthProblemException(OAuth.Problems.TOKEN_USED); if (entry.isExpired()) throw new OAuthProblemException(OAuth.Problems.TOKEN_EXPIRED); // find consumer key, compare with supplied value, if present. if (requestMessage.getConsumerKey() == null) { OAuthProblemException e = new OAuthProblemException(OAuth.Problems.PARAMETER_ABSENT); e.setParameter(OAuth.Problems.OAUTH_PARAMETERS_ABSENT, OAuth.OAUTH_CONSUMER_KEY); throw e; } String consumerKey = entry.consumerKey; if (!consumerKey.equals(requestMessage.getConsumerKey())) throw new OAuthProblemException(OAuth.Problems.CONSUMER_KEY_REFUSED); OAuthConsumer consumer = dataStore.getConsumer(consumerKey); if (consumer == null) throw new OAuthProblemException(OAuth.Problems.CONSUMER_KEY_UNKNOWN); OAuthAccessor accessor = new OAuthAccessor(consumer); accessor.requestToken = entry.token; accessor.tokenSecret = entry.tokenSecret; VALIDATOR.validateMessage(requestMessage, accessor); return entry; }
// Hand out an access token if the consumer key and secret are valid and the user authorized // the requestToken private void createAccessToken( HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException, OAuthException, URISyntaxException { OAuthMessage requestMessage = OAuthServlet.getMessage(servletRequest, null); OAuthEntry entry = getValidatedEntry(requestMessage); if (entry == null) throw new OAuthProblemException(OAuth.Problems.TOKEN_REJECTED); if (entry.callbackToken != null) { // We're using the fixed protocol String clientCallbackToken = requestMessage.getParameter(OAuthConstants.OAUTH_VERIFIER); if (!entry.callbackToken.equals(clientCallbackToken)) { dataStore.disableToken(entry); servletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "This token is not authorized"); return; } } else if (!entry.authorized) { // Old protocol. Catch consumers trying to convert a token to one that's not authorized dataStore.disableToken(entry); servletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "This token is not authorized"); return; } // turn request token into access token OAuthEntry accessEntry = dataStore.convertToAccessToken(entry); sendResponse( servletResponse, OAuth.newList( OAuth.OAUTH_TOKEN, accessEntry.token, OAuth.OAUTH_TOKEN_SECRET, accessEntry.tokenSecret, "user_id", entry.userId)); }
protected void validateSignature(OAuthMessage message, OAuthAccessor accessor) throws OAuthException, IOException, URISyntaxException { message.requireParameters( OAuth.OAUTH_CONSUMER_KEY, OAuth.OAUTH_SIGNATURE_METHOD, OAuth.OAUTH_SIGNATURE); OAuthSignatureMethod.newSigner(message, accessor).validate(message); }
// Loosely based off net.oauth.OAuthServlet, and even more loosely related // to the OAuth specification private MessageInfo parseMessage(HttpRequest request) { MessageInfo info = new MessageInfo(); info.request = request; String method = request.getMethod(); ParsedUrl parsed = new ParsedUrl(request.getUri().toString()); List<OAuth.Parameter> params = Lists.newArrayList(); params.addAll(parsed.getParsedQuery()); if (!validParamLocations.contains(OAuthParamLocation.URI_QUERY)) { // Make sure nothing OAuth related ended up in the query string for (OAuth.Parameter p : params) { if (p.getKey().contains("oauth_")) { throw new RuntimeException("Found unexpected query param " + p.getKey()); } } } // Parse authorization header if (validParamLocations.contains(OAuthParamLocation.AUTH_HEADER)) { String aznHeader = request.getHeader("Authorization"); if (aznHeader != null) { info.aznHeader = aznHeader; for (OAuth.Parameter p : OAuthMessage.decodeAuthorization(aznHeader)) { if (!p.getKey().equalsIgnoreCase("realm")) { params.add(p); } } } } // Parse body info.body = request.getPostBodyAsString(); try { info.rawBody = IOUtils.toByteArray(request.getPostBody()); } catch (IOException e) { throw new RuntimeException("Can't read post body bytes", e); } if (OAuth.isFormEncoded(request.getHeader("Content-Type"))) { params.addAll(OAuth.decodeForm(request.getPostBodyAsString())); // If we're not configured to pass oauth parameters in the post body, double check // that they didn't end up there. if (!validParamLocations.contains(OAuthParamLocation.POST_BODY)) { if (info.body.contains("oauth_")) { throw new RuntimeException("Found unexpected post body data" + info.body); } } } // Return the lot info.message = new OAuthMessage(method, parsed.getLocation(), params); // Check for trusted parameters if (checkTrustedParams) { if (!"foo".equals(OAuthUtil.getParameter(info.message, "oauth_magic"))) { throw new RuntimeException("no oauth_trusted=foo parameter"); } if (!"bar".equals(OAuthUtil.getParameter(info.message, "opensocial_magic"))) { throw new RuntimeException("no opensocial_trusted=foo parameter"); } if (!"quux".equals(OAuthUtil.getParameter(info.message, "xoauth_magic"))) { throw new RuntimeException("no xoauth_magic=quux parameter"); } trustedParamCount += 3; } return info; }
///////////////////// // deal with authorization request private void authorizeRequestToken( HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException, OAuthException, URISyntaxException { OAuthMessage requestMessage = OAuthServlet.getMessage(servletRequest, null); if (requestMessage.getToken() == null) { // MALFORMED REQUEST servletResponse.sendError( HttpServletResponse.SC_BAD_REQUEST, "Authentication token not found"); return; } OAuthEntry entry = dataStore.getEntry(requestMessage.getToken()); if (entry == null) { servletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, "OAuth Entry not found"); return; } OAuthConsumer consumer = dataStore.getConsumer(entry.consumerKey); // Extremely rare case where consumer dissappears if (consumer == null) { servletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, "consumer for entry not found"); return; } // A flag to deal with protocol flaws in OAuth/1.0 Boolean securityThreat_2009_1 = !entry.callbackUrlSigned; // Check for a callback in the oauth entry String callback = entry.callbackUrl; if (callback == null) { // see if there's a callback in the url params callback = requestMessage.getParameter(OAuth.OAUTH_CALLBACK); } if (callback == null) { // see if the consumer has a callback callback = consumer.callbackURL; } // The token is disabled if you try to convert to an access token prior to authorization if (entry.type == OAuthEntry.Type.DISABLED) { servletResponse.sendError( HttpServletResponse.SC_FORBIDDEN, "This token is disabled, please reinitate login"); return; } // Redirect to a UI flow if the token is not authorized if (!entry.authorized) { // TBD -- need to decode encrypted payload somehow.. if (this.oauthAuthorizeAction.startsWith("http")) { // Redirect to authorization page with params // Supply standard set of params // TBD } else { // Use internal forward to a jsp page servletRequest.setAttribute("OAUTH_DATASTORE", dataStore); servletRequest.setAttribute("OAUTH_ENTRY", entry); servletRequest.setAttribute("CALLBACK", callback); servletRequest.setAttribute("TOKEN", entry.token); servletRequest.setAttribute("CONSUMER", consumer); servletRequest.setAttribute("SECURITY_THREAT_2009_1", securityThreat_2009_1); servletRequest .getRequestDispatcher(oauthAuthorizeAction) .forward(servletRequest, servletResponse); } return; } // If we're here then the entry has been authorized // redirect to callback if (callback == null || "oob".equals(callback)) { // consumer did not specify a callback servletResponse.setContentType("text/plain"); PrintWriter out = servletResponse.getWriter(); out.write("Token successfully authorized.\n"); if (entry.callbackToken != null) { // Usability fail. out.write("Please enter code " + entry.callbackToken + " at the consumer."); } } else { callback = OAuth.addParameters(callback, OAuth.OAUTH_TOKEN, entry.token); // Add user_id to the callback callback = OAuth.addParameters(callback, "user_id", entry.userId); if (entry.callbackToken != null) { callback = OAuth.addParameters(callback, OAuthConstants.OAUTH_VERIFIER, entry.callbackToken); } servletResponse.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); servletResponse.setHeader("Location", callback); } }
protected void validate(Map payload, boolean isTrustedConsumer) throws LTIException { // check parameters String lti_message_type = (String) payload.get(BasicLTIConstants.LTI_MESSAGE_TYPE); String lti_version = (String) payload.get(BasicLTIConstants.LTI_VERSION); String oauth_consumer_key = (String) payload.get("oauth_consumer_key"); String resource_link_id = (String) payload.get(BasicLTIConstants.RESOURCE_LINK_ID); String user_id = (String) payload.get(BasicLTIConstants.USER_ID); String context_id = (String) payload.get(BasicLTIConstants.CONTEXT_ID); boolean launch = true; if (BasicLTIUtil.equals(lti_message_type, "basic-lti-launch-request")) { launch = true; } else if (BasicLTIUtil.equals(lti_message_type, "ContentItemSelectionRequest")) { launch = false; } else { throw new LTIException("launch.invalid", "lti_message_type=" + lti_message_type, null); } if (!BasicLTIUtil.equals(lti_version, "LTI-1p0")) { throw new LTIException("launch.invalid", "lti_version=" + lti_version, null); } if (BasicLTIUtil.isBlank(oauth_consumer_key)) { throw new LTIException("launch.missing", "oauth_consumer_key", null); } if (launch && BasicLTIUtil.isBlank(resource_link_id)) { throw new LTIException("launch.missing", "resource_link_id", null); } if (BasicLTIUtil.isBlank(user_id)) { throw new LTIException("launch.missing", "user_id", null); } if (M_log.isDebugEnabled()) { M_log.debug("user_id=" + user_id); } // check tool_id String tool_id = (String) payload.get("tool_id"); if (tool_id == null) { throw new LTIException("launch.tool_id.required", null, null); } // Trim off the leading slash and any trailing space tool_id = tool_id.substring(1).trim(); if (M_log.isDebugEnabled()) { M_log.debug("tool_id=" + tool_id); } // store modified tool_id back in payload payload.put("tool_id", tool_id); final String allowedToolsConfig = ServerConfigurationService.getString("basiclti.provider.allowedtools", ""); final String[] allowedTools = allowedToolsConfig.split(":"); final List<String> allowedToolsList = Arrays.asList(allowedTools); if (launch && allowedTools != null && !allowedToolsList.contains(tool_id)) { throw new LTIException("launch.tool.notallowed", tool_id, null); } final Tool toolCheck = ToolManager.getTool(tool_id); if (launch && toolCheck == null) { throw new LTIException("launch.tool.notfound", tool_id, null); } // Check for the ext_sakai_provider_eid param. If set, this will contain the eid that we are to // use // in place of using the user_id parameter // WE still need that parameter though, so translate it from the given eid. boolean useProvidedEid = false; String ext_sakai_provider_eid = (String) payload.get(BasicLTIConstants.EXT_SAKAI_PROVIDER_EID); if (BasicLTIUtil.isNotBlank(ext_sakai_provider_eid)) { useProvidedEid = true; try { user_id = UserDirectoryService.getUserId(ext_sakai_provider_eid); } catch (Exception e) { M_log.error(e.getLocalizedMessage(), e); throw new LTIException( "launch.provided.eid.invalid", "ext_sakai_provider_eid=" + ext_sakai_provider_eid, e); } } if (M_log.isDebugEnabled()) { M_log.debug("ext_sakai_provider_eid=" + ext_sakai_provider_eid); } // Contextualize the context_id with the OAuth consumer key // Also use the resource_link_id for the context_id if we did not get a context_id // BLTI-31: if trusted, context_id is required and use the param without modification if (BasicLTIUtil.isBlank(context_id)) { if (isTrustedConsumer) { throw new LTIException("launch.missing", context_id, null); } else { context_id = "res:" + resource_link_id; payload.put(BasicLTIConstants.CONTEXT_ID, context_id); } } // Check if context_id is simply a ~. If so, get the id of that user's My Workspace site // and use that to construct the full context_id if (BasicLTIUtil.equals(context_id, "~")) { if (useProvidedEid) { String userSiteId = null; try { userSiteId = SiteService.getUserSiteId(user_id); } catch (Exception e) { M_log.warn("Failed to get My Workspace site for user_id:" + user_id); M_log.error(e.getLocalizedMessage(), e); throw new LTIException("launch.user.site.unknown", "user_id=" + user_id, e); } context_id = userSiteId; payload.put(BasicLTIConstants.CONTEXT_ID, context_id); } } if (M_log.isDebugEnabled()) { M_log.debug("context_id=" + context_id); } // Lookup the secret final String configPrefix = "basiclti.provider." + oauth_consumer_key + "."; final String oauth_secret = ServerConfigurationService.getString(configPrefix + "secret", null); if (oauth_secret == null) { throw new LTIException("launch.key.notfound", oauth_consumer_key, null); } final OAuthMessage oam = (OAuthMessage) payload.get("oauth_message"); final String forcedURIScheme = ServerConfigurationService.getString("basiclti.provider.forcedurischeme", null); if (forcedURIScheme != null) { try { URI testURI = new URI(oam.URL); URI newURI = new URI(forcedURIScheme, testURI.getSchemeSpecificPart(), null); oam.URL = newURI.toString(); } catch (URISyntaxException use) { } } final OAuthValidator oav = new SimpleOAuthValidator(); final OAuthConsumer cons = new OAuthConsumer( "about:blank#OAuth+CallBack+NotUsed", oauth_consumer_key, oauth_secret, null); final OAuthAccessor acc = new OAuthAccessor(cons); String base_string = null; try { base_string = OAuthSignatureMethod.getBaseString(oam); } catch (Exception e) { M_log.error(e.getLocalizedMessage(), e); base_string = null; } try { oav.validateMessage(oam, acc); } catch (Exception e) { M_log.warn("Provider failed to validate message"); M_log.warn(e.getLocalizedMessage(), e); if (base_string != null) { M_log.warn(base_string); } throw new LTIException("launch.no.validate", context_id, e); } final Session sess = SessionManager.getCurrentSession(); if (sess == null) { throw new LTIException("launch.no.session", context_id, null); } }