All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.uiuc.ncsa.myproxy.oa4mp.oauth2.servlet.OA2AuthorizedServlet Maven / Gradle / Ivy

The newest version!
package edu.uiuc.ncsa.myproxy.oa4mp.oauth2.servlet;

import edu.uiuc.ncsa.myproxy.oa4mp.oauth2.OA2ServiceTransaction;
import edu.uiuc.ncsa.myproxy.oa4mp.oauth2.storage.UsernameFindable;
import edu.uiuc.ncsa.myproxy.oa4mp.server.servlet.AbstractInitServlet;
import edu.uiuc.ncsa.security.core.exceptions.NFWException;
import edu.uiuc.ncsa.security.delegation.server.ServiceTransaction;
import edu.uiuc.ncsa.security.delegation.server.request.AGResponse;
import edu.uiuc.ncsa.security.delegation.server.request.IssuerResponse;
import edu.uiuc.ncsa.security.delegation.token.AuthorizationGrant;
import edu.uiuc.ncsa.security.oauth_2_0.*;
import edu.uiuc.ncsa.security.oauth_2_0.server.OA2Claims;
import net.sf.json.JSONObject;
import org.apache.http.HttpStatus;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Map;
import java.util.StringTokenizer;

import static edu.uiuc.ncsa.security.oauth_2_0.OA2Constants.*;

/**
 * 

Created by Jeff Gaynor
* on 10/3/13 at 2:01 PM */ public class OA2AuthorizedServlet extends AbstractInitServlet { @Override protected void doIt(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Throwable { //printAllParameters(httpServletRequest); String callback = httpServletRequest.getParameter(OA2Constants.REDIRECT_URI); if (httpServletRequest.getParameterMap().containsKey(OA2Constants.REQUEST_URI)) { throw new OA2RedirectableError(OA2Errors.REQUEST_URI_NOT_SUPPORTED, "Request uri not supported by this server", httpServletRequest.getParameter(OA2Constants.STATE), callback); } if (httpServletRequest.getParameterMap().containsKey(OA2Constants.REQUEST)) { throw new OA2RedirectableError(OA2Errors.REQUEST_NOT_SUPPORTED, "Request not supported by this server", httpServletRequest.getParameter(OA2Constants.STATE), callback); } if (!httpServletRequest.getParameterMap().containsKey(OA2Constants.RESPONSE_TYPE)) { throw new OA2RedirectableError(OA2Errors.INVALID_REQUEST, "no response type", httpServletRequest.getParameter(OA2Constants.STATE), callback); } if (CheckIdTokenHint(httpServletRequest, httpServletResponse, callback)) return; super.doIt(httpServletRequest, httpServletResponse); } /** * In this case, a previous request to the token endpoint returned an ID token. If this is sent to * this endpoint, we are to check that there is an active logon for the user (=there is a transaction * for that name here) and return a success but no body. Otherwise, we throw an exception. * * @param httpServletRequest * @param httpServletResponse * @param callback * @return */ protected boolean CheckIdTokenHint(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, String callback) { if (!httpServletRequest.getParameterMap().containsKey(ID_TOKEN_HINT)) { return false; } UsernameFindable ufStore = null; String rawIDToken = String.valueOf(httpServletRequest.getParameterMap().get(ID_TOKEN_HINT)); JSONObject idToken = IDTokenUtil.readIDToken(rawIDToken); String state = httpServletRequest.getParameter(STATE); String username = null; if (idToken.containsKey(OA2Claims.SUBJECT)) { username = idToken.getString(OA2Claims.SUBJECT); } else { } try { ufStore = (UsernameFindable) getTransactionStore(); OA2ServiceTransaction t = ufStore.getByUsername(username); if (t != null) { // Then there is a transaction, so the user authenticated successfully. if (idToken.containsKey(OA2Claims.AUDIENCE)) { if (!t.getClient().getIdentifierString().equals(idToken.getString(OA2Claims.AUDIENCE))) { // The wrong client for this user is attempting the request. That is not allowed. throw new OA2RedirectableError(OA2Errors.REQUEST_NOT_SUPPORTED, "Incorrect aud parameter in the ID token. This request is not supported on this server", state, callback); } } else { // The client that is associated with this user must be supplied. throw new OA2RedirectableError(OA2Errors.REQUEST_NOT_SUPPORTED, "No aud parameter in the ID token. This request is not supported on this server", state, callback); } httpServletResponse.setStatus(HttpStatus.SC_OK); // The spec does not state that anything is returned, just a positive response. return true; } } catch (IOException e) { // Really something is probably wrong with the class structure is this fails... throw new NFWException("Internal error: Could not cast the store to a username findable store."); } throw new OA2RedirectableError(OA2Errors.LOGIN_REQUIRED, "Login required.", state, callback); } @Override public ServiceTransaction verifyAndGet(IssuerResponse iResponse) throws UnsupportedEncodingException { AGResponse agResponse = (AGResponse) iResponse; Map params = agResponse.getParameters(); // Since the state (if present) has to be returned with any error message, we have to see if there is one // there first. String state = null; if (params.containsKey(STATE)) { state = params.get(STATE); } //Spec says that the redirect must match one of the ones stored and if not, the request is rejected. String givenRedirect = params.get(REDIRECT_URI); OA2ClientCheck.check(agResponse.getClient(), givenRedirect); // by this point it has been verified that the redirect uri is valid. String rawSecret = params.get(CLIENT_SECRET); if (rawSecret != null) { info("Client is sending secret in initial request. Though not forbidden by the protocol this is discouraged."); if(!agResponse.getClient().getSecret().equals(rawSecret)){ info("And for what it is worth, the client sent along an incorrect secret too..."); } } String nonce = params.get(NONCE); // FIX for OAUTH-180. Server must support clients that do not use a nonce. Just log it and rock on. if (nonce == null || nonce.length() == 0) { info("No nonce in initial request for " + ((AGResponse) iResponse).getClient().getIdentifierString()); } else { NonceHerder.putNonce(nonce); // Don't check it, just store it and return it later. } if (params.containsKey(DISPLAY)) { if (!params.get(DISPLAY).equals(DISPLAY_PAGE)) { throw new OA2RedirectableError(OA2Errors.INVALID_REQUEST, "Only " + DISPLAY + "=" + DISPLAY_PAGE + " is supported", state, givenRedirect); } } String rawScopes = params.get(SCOPE); if (rawScopes == null || rawScopes.length() == 0) { throw new OA2RedirectableError(OA2Errors.INVALID_SCOPE, "Missing scopes parameter.", state, givenRedirect); } StringTokenizer stringTokenizer = new StringTokenizer(rawScopes); ArrayList scopes = new ArrayList<>(); boolean hasOpenIDScope = false; while (stringTokenizer.hasMoreTokens()) { String x = stringTokenizer.nextToken(); if (!OA2Scopes.ScopeUtil.hasScope(x)) { throw new OA2RedirectableError(OA2Errors.INVALID_SCOPE, "Unrecognized scope \"" + x + "\"", state, givenRedirect); } if (x.equals(OA2Scopes.SCOPE_OPENID)) hasOpenIDScope = true; scopes.add(x); } if (!hasOpenIDScope) throw new OA2RedirectableError(OA2Errors.INVALID_REQUEST, "Scopes must contain openid", state, givenRedirect); OA2ServiceTransaction st = createNewTransaction(agResponse.getGrant()); st.setScopes(scopes); st.setAuthGrantValid(false); st.setAccessTokenValid(false); st.setCallback(URI.create(params.get(REDIRECT_URI))); // fine if the nonce is null or empty, just set what they sent. st.setNonce(nonce); // We can't support this because the spec says we must re-authenticate the user. We should have to track this // in all subsequent attempts. Since all requests have an expiration date, this parameter is redundant in any case. if(agResponse.getParameters().containsKey(OA2Constants.MAX_AGE)){ throw new OA2RedirectableError(OA2Errors.INVALID_REQUEST, "The " + OA2Constants.MAX_AGE +" parameter is not supported at this time.", state, givenRedirect); } // Store the callback the user needs to use for this request, since the spec allows for many. // and now check for a bunch of stuff that might fail. checkPrompts(params); if (params.containsKey(REQUEST)) { throw new OA2RedirectableError(OA2Errors.REQUEST_NOT_SUPPORTED, "The \"request\" parameter is not supported on this server", state, givenRedirect); } if (params.containsKey(REQUEST_URI)) { throw new OA2RedirectableError(OA2Errors.REQUEST_URI_NOT_SUPPORTED, "The \"request_uri\" parameter is not supported on this server", state, givenRedirect); } return st; } protected OA2ServiceTransaction createNewTransaction(AuthorizationGrant grant) { return new OA2ServiceTransaction(grant); } /** * Basically, if the prompt parameter is there, we only support the login option. * * @param map */ protected void checkPrompts(Map map) { if (!map.containsKey(PROMPT)) return; //nix to do String prompts = map.get(PROMPT); // now we have tos ee what is in it. StringTokenizer st = new StringTokenizer(prompts); ArrayList prompt = new ArrayList<>(); while (st.hasMoreElements()) { prompt.add(st.nextToken()); } // CIL-91 if prompt = none is passed in, return an error with login_required as the message. if (!prompt.contains(PROMPT_NONE) && prompt.size() == 0) { throw new OA2RedirectableError(OA2Errors.LOGIN_REQUIRED, "A login is required on this server", map.get(OA2Constants.STATE)); } if (prompt.contains(PROMPT_NONE) && 1 < prompt.size()) { throw new OA2RedirectableError(OA2Errors.INVALID_REQUEST, "You cannot specify \"none\" for the prompt and any other option", map.get(OA2Constants.STATE)); } if (prompt.contains(PROMPT_LOGIN)) return; // At this point there is neither a "none" or a "login" and we don's support anything else. throw new OA2RedirectableError(OA2Errors.LOGIN_REQUIRED, "You must specify \"login\" as an option", map.get(OA2Constants.STATE)); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy