package fi.otavanopisto.pyramus.plugin.googleoauth; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import net.sf.json.JSONObject; import org.apache.commons.lang3.StringUtils; import org.scribe.builder.ServiceBuilder; import org.scribe.model.OAuthRequest; import org.scribe.model.Response; import org.scribe.model.Token; import org.scribe.model.Verb; import org.scribe.model.Verifier; import org.scribe.oauth.OAuthService; import fi.internetix.smvc.controllers.RequestContext; import fi.otavanopisto.pyramus.dao.DAOFactory; import fi.otavanopisto.pyramus.dao.base.PersonDAO; import fi.otavanopisto.pyramus.dao.system.SettingDAO; import fi.otavanopisto.pyramus.dao.system.SettingKeyDAO; import fi.otavanopisto.pyramus.dao.users.UserIdentificationDAO; import fi.otavanopisto.pyramus.domainmodel.base.Person; import fi.otavanopisto.pyramus.domainmodel.users.User; import fi.otavanopisto.pyramus.domainmodel.users.UserIdentification; import fi.otavanopisto.pyramus.plugin.auth.AuthenticationException; import fi.otavanopisto.pyramus.plugin.auth.ExternalAuthenticationProvider; import fi.otavanopisto.pyramus.plugin.auth.LocalUserMissingException; import fi.otavanopisto.pyramus.plugin.googleoauth.scribe.GoogleApi20; public class GoogleOauthAuthorizationStrategy implements ExternalAuthenticationProvider { private static final String GOOGLE_LOGOUT_URL = "https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=%s"; private static final String GOOGLE_LOGGED_IN_ATTRIBUTE = "googleLoggedIn"; public GoogleOauthAuthorizationStrategy() { } public String getName() { return "Google-oauth"; } @Override public String logout(RequestContext requestContext) { HttpSession session = requestContext.getRequest().getSession(false); if (!isLoggedInToGoogle(session)) { return null; } else { String logoutUrl = String.format("%s/users/logout.page", getBaseUrl(requestContext)); String redirectUrl = requestContext.getString("redirectUrl"); if (StringUtils.isNotBlank(redirectUrl)) { logoutUrl = String.format("%s?redirectUrl=%s", logoutUrl, redirectUrl); } try { return String.format(GOOGLE_LOGOUT_URL, logoutUrl); } finally { setGoogleLoggedIn(session, false); } } } private boolean isLoggedInToGoogle(HttpSession session) { return Boolean.TRUE.equals(session.getAttribute(GOOGLE_LOGGED_IN_ATTRIBUTE)); } private void setGoogleLoggedIn(HttpSession session, Boolean value) { session.setAttribute(GOOGLE_LOGGED_IN_ATTRIBUTE, value); } public void performDiscovery(RequestContext requestContext) { OAuthService service = new ServiceBuilder() .provider(GoogleApi20.class) .apiKey(this.getClientId()) .apiSecret(this.getClientSecret()) .callback(this.getRedirectUrl()) .scope(this.getScope()) .build(); requestContext.setRedirectURL(service.getAuthorizationUrl(null)); } public User processResponse(RequestContext requestContext) throws AuthenticationException { HttpServletRequest req = requestContext.getRequest(); HttpSession session = req.getSession(); String authCode = req.getParameter("code"); Verifier verifier = new Verifier(authCode); OAuthService service = new ServiceBuilder() .provider(GoogleApi20.class) .apiKey(this.getClientId()) .apiSecret(this.getClientSecret()) .callback(this.getRedirectUrl()) .scope(this.getScope()) .build(); Token accessToken = service.getAccessToken(null, verifier); OAuthRequest request = new OAuthRequest(Verb.GET, "https://www.googleapis.com/oauth2/v1/userinfo?alt=json"); service.signRequest(accessToken, request); Response response = request.send(); JSONObject userInfo = JSONObject.fromObject(response.getBody()); if (userInfo != null) { try { return processLogin(userInfo.getString("id"), userInfo.getString("email")); } finally { setGoogleLoggedIn(session, true); } } else { throw new AuthenticationException(AuthenticationException.EXTERNAL_LOGIN_SERVER_ERROR); } } private User processLogin(String externalId, String email) throws AuthenticationException{ UserIdentificationDAO userIdentificationDAO = DAOFactory.getInstance().getUserIdentificationDAO(); PersonDAO personDAO = DAOFactory.getInstance().getPersonDAO(); // Trim the email address email = email != null ? email.trim() : null; Person emailPerson = personDAO.findByUniqueEmail(email); if (emailPerson == null) { throw new LocalUserMissingException(email); } UserIdentification userIdentification = userIdentificationDAO.findByAuthSourceAndExternalId(getName(), externalId); if (userIdentification != null) { // User has identified by this auth source before if (!emailPerson.getId().equals(userIdentification.getPerson().getId())) { throw new AuthenticationException(AuthenticationException.EMAIL_BELONGS_TO_ANOTHER_PERSON); } } else { userIdentificationDAO.create(emailPerson, getName(), externalId); } return emailPerson.getDefaultUser(); } private String getClientId() { SettingDAO settingDAO = DAOFactory.getInstance().getSettingDAO(); SettingKeyDAO settingKeyDAO = DAOFactory.getInstance().getSettingKeyDAO(); return settingDAO.findByKey(settingKeyDAO.findByName("google.oauth.clientid")).getValue(); } private String getClientSecret() { SettingDAO settingDAO = DAOFactory.getInstance().getSettingDAO(); SettingKeyDAO settingKeyDAO = DAOFactory.getInstance().getSettingKeyDAO(); return settingDAO.findByKey(settingKeyDAO.findByName("google.oauth.clientsecret")).getValue(); } private String getRedirectUrl() { SettingDAO settingDAO = DAOFactory.getInstance().getSettingDAO(); SettingKeyDAO settingKeyDAO = DAOFactory.getInstance().getSettingKeyDAO(); return settingDAO.findByKey(settingKeyDAO.findByName("google.oauth.redirecturl")).getValue(); } private String getScope() { return "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile"; } private String getBaseUrl(RequestContext requestContext) { HttpServletRequest request = requestContext.getRequest(); String currentURL = request.getRequestURL().toString(); String pathInfo = request.getRequestURI(); return currentURL.substring(0, currentURL.length() - pathInfo.length()) + request.getContextPath(); } }