package com.dexels.oauth.web; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.security.GeneralSecurityException; import java.util.HashSet; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.dexels.oauth.api.AuthorizationToken; import com.dexels.oauth.api.AuthorizationTokenStoreFactory; import com.dexels.oauth.api.Scope; import com.dexels.oauth.web.exceptions.OAuthClientException; import com.google.crypto.tink.subtle.AesGcmJce; import com.google.crypto.tink.subtle.Base64; public abstract class OAuthCommandBaseWeb extends OAuthCommandBase { private static final Logger logger = LoggerFactory.getLogger(OAuthCommandBaseWeb.class); protected String username; protected Set scopes = new HashSet<>(); protected String redirectURL; public OAuthCommandBaseWeb(HttpServletRequest request, HttpServletResponse response) throws OAuthClientException { super(request, response); redirectURL = request.getParameter("redirect_url"); if (redirectURL == null) { throw new OAuthClientException("Missing redirect_url parameter"); } if (client.getRedirectURL() != null && !client.getRedirectURL().equals(redirectURL)) { throw new OAuthClientException("Invalid redirect_url parameter"); } String encryptedUsername = request.getParameter("extra"); if (encryptedUsername != null && !encryptedUsername.equals("")) { try { username = decrypt(encryptedUsername); } catch (UnsupportedEncodingException | GeneralSecurityException e) { throw new OAuthClientException("Invalid extra"); } } } public void sendToRegisterConfirmed() throws IOException { sendAbsoluteRedirect("/auth/register-confirm.html?" + request.getQueryString()); } public void sendToLogin(OAuthError error, String errorReference) throws IOException { sendAbsoluteRedirect("/auth/login.html?" + request.getQueryString() + errorString(error, errorReference)); } public void sendToAddApplication(String username, OAuthError error, String errorReference) throws IOException { try { sendAbsoluteRedirect("/auth/add-application.html?" + request.getQueryString() + "&extra=" + encrypt(username) + errorString(error, errorReference)); } catch (GeneralSecurityException e) { throw new IOException(e); } } public void sendToPasswordReset(OAuthError error, String errorReference) throws IOException { sendAbsoluteRedirect("/auth/password-reset.html?" + request.getQueryString() + errorString(error, errorReference)); } public void sendToPasswordResetConfirm() throws IOException { sendAbsoluteRedirect("/auth/password-reset-confirm.html?" + request.getQueryString()); } public void sendToActivateSuccess() throws IOException { sendAbsoluteRedirect("/auth/activate-success.html?" + request.getQueryString()); } public void sendToActivateFailure(OAuthError error, String errorReference) throws IOException { sendAbsoluteRedirect("/auth/activate-failure.html?" + request.getQueryString() + errorString(error, errorReference)); } public void sendToRegister(OAuthError error, String errorReference) throws IOException { sendAbsoluteRedirect("/auth/register.html?" + request.getQueryString() + errorString(error, errorReference)); } public void sendToOtp() throws IOException { sendAbsoluteRedirect("/auth/otp.html?" + request.getQueryString()); } public void sendToScopeAccept() throws IOException { sendAbsoluteRedirect("/auth/accept-scope.html?" + request.getQueryString()); } public void sendToPasswordForgot(OAuthError error, String errorReference) throws IOException { sendAbsoluteRedirect("/auth/password-forgot.html?" + request.getQueryString() + errorString(error, errorReference)); } public void sendToPasswordForgotSent() throws IOException { sendAbsoluteRedirect("/auth/password-forgot-sent.html?" + request.getQueryString()); } public void sendAbsoluteRedirect(String relative) throws IOException { response.sendRedirect(createAbsolute(relative)); } private String errorString(OAuthError error, String errorReference) { if (error == null) { return ""; } else { return "&error=" + error + "&ref=" + errorReference; } } private String encrypt(String plainText) throws GeneralSecurityException, UnsupportedEncodingException { AesGcmJce agjEncryption = new AesGcmJce(OAuthServlet.getEncryptionString().getBytes()); return Base64.encodeToString(agjEncryption.encrypt(plainText.getBytes(), "".getBytes()), Base64.URL_SAFE); } private String decrypt(String encrypted) throws GeneralSecurityException, UnsupportedEncodingException { AesGcmJce agjEncryption = new AesGcmJce(OAuthServlet.getEncryptionString().getBytes()); return new String(agjEncryption.decrypt(Base64.decode(encrypted, Base64.URL_SAFE), "".getBytes())); } protected void processLogin(String username) throws IOException { // The user is valid, but before we can proceed to make some kind of token // the user needs to explicitly tell us he will accept the required/optional // scopes if (!scopes.isEmpty() || !client.getRequiredScopes().isEmpty()) { logger.debug("Need to confirm scopes, id: {}", client.getClientId()); sendToScopeAccept(); return; } completeLogin(username); } protected void completeLogin(String username) throws IOException { AuthorizationToken authorization = AuthorizationTokenStoreFactory.getInstance().generate(client, username, scopes, redirectURL); AuthorizationTokenStoreFactory.getInstance().insert(tenant, authorization); if (redirectURL.endsWith("?")) { redirectURL = redirectURL.substring(0, redirectURL.length() - 1); // strip trailing ? } boolean hasQueryParams = redirectURL.contains("?"); String redirect = String.format("%s%scode=%s", redirectURL, (hasQueryParams ? "&" : "?"), authorization.getCode()); String state = request.getParameter("state"); if (state != null) { redirect += "&state=" + URLEncoder.encode(state, "UTF-8"); } logger.debug("Redirecting user {} for clientid {} to {}", username, client.getClientId(), redirect); response.sendRedirect(redirect); } }