From 2c0555f90ecb61a068754569e2624a6569b89a2c Mon Sep 17 00:00:00 2001 From: Fabrice Bacchella Date: Fri, 15 May 2015 22:36:45 +0200 Subject: [PATCH] A patch that allows to extract a new user informations from the HTTP session if the webapp container can fill it. --- src/main/distrib/data/defaults.properties | 16 + .../manager/AuthenticationManager.java | 48 ++ .../tests/AuthenticationManagerTest.java | 675 +++++++++++++++++- 3 files changed, 722 insertions(+), 17 deletions(-) diff --git a/src/main/distrib/data/defaults.properties b/src/main/distrib/data/defaults.properties index 0857ccf6..7be50c80 100644 --- a/src/main/distrib/data/defaults.properties +++ b/src/main/distrib/data/defaults.properties @@ -1610,6 +1610,22 @@ federation.sets = # SINCE 1.3.0 realm.container.autoCreateAccounts = false +# A set of mapping used to map HTTP session attributes to user informations +# They are used if realm.container.autoCreateAccounts is set to true and +# the webapp container used can fill the session with user informations +# +# SINCE 1.7.0 +realm.container.autoAccounts.displayName = +realm.container.autoAccounts.emailAddress = +realm.container.autoAccounts.locale = + +# If the user's created by the webapp container is given this role, +# the user created will be a admin user. +# +# SINCE 1.7.0 +realm.container.autoAccounts.adminRole = + + # Allow or prohibit Windows guest account logins # # SINCE 1.3.0 diff --git a/src/main/java/com/gitblit/manager/AuthenticationManager.java b/src/main/java/com/gitblit/manager/AuthenticationManager.java index 29221e6f..cbf0a1bd 100644 --- a/src/main/java/com/gitblit/manager/AuthenticationManager.java +++ b/src/main/java/com/gitblit/manager/AuthenticationManager.java @@ -215,6 +215,29 @@ public class AuthenticationManager implements IAuthenticationManager { user.displayName = username; user.password = Constants.EXTERNAL_ACCOUNT; user.accountType = AccountType.CONTAINER; + + // Try to extract user's informations for the session + // it uses "realm.container.autoAccounts.*" as the attribute name to look for + HttpSession session = httpRequest.getSession(); + String emailAddress = resolveAttribute(session, Keys.realm.container.autoAccounts.emailAddress); + if(emailAddress != null) { + user.emailAddress = emailAddress; + } + String displayName = resolveAttribute(session, Keys.realm.container.autoAccounts.displayName); + if(displayName != null) { + user.displayName = displayName; + } + String userLocale = resolveAttribute(session, Keys.realm.container.autoAccounts.locale); + if(userLocale != null) { + user.getPreferences().setLocale(userLocale); + } + String adminRole = settings.getString(Keys.realm.container.autoAccounts.adminRole, null); + if(adminRole != null && ! adminRole.isEmpty()) { + if(httpRequest.isUserInRole(adminRole)) { + user.canAdmin = true; + } + } + userManager.updateUserModel(user); flagSession(httpRequest, AuthenticationType.CONTAINER); logger.debug(MessageFormat.format("{0} authenticated and created by servlet container principal from {1}", @@ -293,6 +316,31 @@ public class AuthenticationManager implements IAuthenticationManager { } return null; } + + /** + * Extract given attribute from the session and return it's content + * it return null if attributeMapping is empty, or if the value is + * empty + * + * @param session The user session + * @param attributeMapping + * @return + */ + private String resolveAttribute(HttpSession session, String attributeMapping) { + String attributeName = settings.getString(attributeMapping, null); + if(StringUtils.isEmpty(attributeName)) { + return null; + } + Object attributeValue = session.getAttribute(attributeName); + if(attributeValue == null) { + return null; + } + String value = attributeValue.toString(); + if(value.isEmpty()) { + return null; + } + return value; + } /** * Authenticate a user based on a public key. diff --git a/src/test/java/com/gitblit/tests/AuthenticationManagerTest.java b/src/test/java/com/gitblit/tests/AuthenticationManagerTest.java index 0cdee6cb..d6ca89c6 100644 --- a/src/test/java/com/gitblit/tests/AuthenticationManagerTest.java +++ b/src/test/java/com/gitblit/tests/AuthenticationManagerTest.java @@ -15,15 +15,44 @@ */ package com.gitblit.tests; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import javax.servlet.AsyncContext; +import javax.servlet.DispatcherType; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionContext; +import javax.servlet.http.HttpUpgradeHandler; +import javax.servlet.http.Part; import org.junit.Test; +import com.gitblit.IUserService; +import com.gitblit.Keys; import com.gitblit.manager.AuthenticationManager; import com.gitblit.manager.IAuthenticationManager; -import com.gitblit.manager.IUserManager; +import com.gitblit.manager.IRuntimeManager; import com.gitblit.manager.RuntimeManager; import com.gitblit.manager.UserManager; +import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; import com.gitblit.tests.mock.MemorySettings; import com.gitblit.utils.XssFilter; @@ -35,27 +64,596 @@ import com.gitblit.utils.XssFilter.AllowXssFilter; * @author James Moger * */ +@SuppressWarnings("deprecation") public class AuthenticationManagerTest extends GitblitUnitTest { - IUserManager users; + UserManager users; + + private static final class DummyHttpServletRequest implements HttpServletRequest { + + @Override + public Object getAttribute(String name) { + return null; + } + + @Override + public Enumeration getAttributeNames() { + return null; + } + + @Override + public String getCharacterEncoding() { + return null; + } + + @Override + public void setCharacterEncoding(String env) + throws UnsupportedEncodingException { + } + + @Override + public int getContentLength() { + return 0; + } + + @Override + public long getContentLengthLong() { + return 0; + } + + @Override + public String getContentType() { + return null; + } + + @Override + public ServletInputStream getInputStream() throws IOException { + return null; + } + + @Override + public String getParameter(String name) { + return null; + } + + @Override + public Enumeration getParameterNames() { + return null; + } + + @Override + public String[] getParameterValues(String name) { + return null; + } + + @Override + public Map getParameterMap() { + return null; + } + + @Override + public String getProtocol() { + return null; + } + + @Override + public String getScheme() { + return null; + } + + @Override + public String getServerName() { + return null; + } + + @Override + public int getServerPort() { + return 0; + } + + @Override + public BufferedReader getReader() throws IOException { + return null; + } + + @Override + public String getRemoteAddr() { + return null; + } + + @Override + public String getRemoteHost() { + return null; + } + + @Override + public void setAttribute(String name, Object o) { + } + + @Override + public void removeAttribute(String name) { + } + + @Override + public Locale getLocale() { + return null; + } + + @Override + public Enumeration getLocales() { + return null; + } + + @Override + public boolean isSecure() { + return false; + } + + @Override + public RequestDispatcher getRequestDispatcher(String path) { + return null; + } + + @Override + public String getRealPath(String path) { + return null; + } + + @Override + public int getRemotePort() { + return 0; + } + + @Override + public String getLocalName() { + return null; + } + + @Override + public String getLocalAddr() { + return null; + } + + @Override + public int getLocalPort() { + return 0; + } + + @Override + public ServletContext getServletContext() { + return null; + } + + @Override + public AsyncContext startAsync() throws IllegalStateException { + return null; + } + + @Override + public AsyncContext startAsync(ServletRequest servletRequest, + ServletResponse servletResponse) + throws IllegalStateException { + return null; + } + + @Override + public boolean isAsyncStarted() { + return false; + } + + @Override + public boolean isAsyncSupported() { + return false; + } + + @Override + public AsyncContext getAsyncContext() { + return null; + } + + @Override + public DispatcherType getDispatcherType() { + return null; + } + + @Override + public String getAuthType() { + return null; + } + + @Override + public Cookie[] getCookies() { + return null; + } + + @Override + public long getDateHeader(String name) { + return 0; + } + + @Override + public String getHeader(String name) { + return null; + } + + @Override + public Enumeration getHeaders(String name) { + return null; + } + + @Override + public Enumeration getHeaderNames() { + return null; + } + + @Override + public int getIntHeader(String name) { + return 0; + } + + @Override + public String getMethod() { + return null; + } + + @Override + public String getPathInfo() { + return null; + } + + @Override + public String getPathTranslated() { + return null; + } + + @Override + public String getContextPath() { + return null; + } + + @Override + public String getQueryString() { + return null; + } + + @Override + public String getRemoteUser() { + return null; + } + + @Override + public boolean isUserInRole(String role) { + if(role != null && "admin".equals(role)) { + return true; + } + return false; + } + + @Override + public Principal getUserPrincipal() { + return new Principal(){ + @Override + public String getName() { + return "sunnyjim"; + } + + }; + } + + @Override + public String getRequestedSessionId() { + return null; + } + + @Override + public String getRequestURI() { + return null; + } + + @Override + public StringBuffer getRequestURL() { + return null; + } + + @Override + public String getServletPath() { + return null; + } + + @Override + public HttpSession getSession(boolean create) { + return null; + } + + final Map sessionAttributes = new HashMap(); + @Override + public HttpSession getSession() { + return new HttpSession() { + + @Override + public long getCreationTime() { + return 0; + } + + @Override + public String getId() { + return null; + } + + @Override + public long getLastAccessedTime() { + return 0; + } - MemorySettings getSettings() { - return new MemorySettings(new HashMap()); - } + @Override + public ServletContext getServletContext() { + return null; + } - IAuthenticationManager newAuthenticationManager() { - XssFilter xssFilter = new AllowXssFilter(); - RuntimeManager runtime = new RuntimeManager(getSettings(), xssFilter, GitBlitSuite.BASEFOLDER).start(); - users = new UserManager(runtime, null).start(); - AuthenticationManager auth = new AuthenticationManager(runtime, users).start(); - return auth; - } + @Override + public void setMaxInactiveInterval(int interval) { + } - @Test - public void testAuthenticate() throws Exception { - IAuthenticationManager auth = newAuthenticationManager(); + @Override + public int getMaxInactiveInterval() { + return 0; + } - UserModel user = new UserModel("sunnyjim"); + @Override + public HttpSessionContext getSessionContext() { + return null; + } + + @Override + public Object getAttribute(String name) { + return sessionAttributes.get(name); + } + + @Override + public Object getValue(String name) { + return null; + } + + @Override + public Enumeration getAttributeNames() { + return Collections.enumeration(sessionAttributes.keySet()); + } + + @Override + public String[] getValueNames() { + return null; + } + + @Override + public void setAttribute(String name, + Object value) { + } + + @Override + public void putValue(String name, Object value) { + } + + @Override + public void removeAttribute(String name) { + } + + @Override + public void removeValue(String name) { + } + + @Override + public void invalidate() { + } + + @Override + public boolean isNew() { + return false; + } + + }; + } + + @Override + public String changeSessionId() { + return null; + } + + @Override + public boolean isRequestedSessionIdValid() { + return false; + } + + @Override + public boolean isRequestedSessionIdFromCookie() { + return false; + } + + @Override + public boolean isRequestedSessionIdFromURL() { + return false; + } + + @Override + public boolean isRequestedSessionIdFromUrl() { + return false; + } + + @Override + public boolean authenticate(HttpServletResponse response) + throws IOException, ServletException { + return false; + } + + @Override + public void login(String username, String password) + throws ServletException { + } + + @Override + public void logout() throws ServletException { + } + + @Override + public Collection getParts() throws IOException, + ServletException { + return null; + } + + @Override + public Part getPart(String name) throws IOException, + ServletException { + return null; + } + + @Override + public T upgrade( + Class handlerClass) throws IOException, + ServletException { + return null; + } + + } + + HashMap settings = new HashMap(); + + MemorySettings getSettings() { + return new MemorySettings(settings); + } + + IAuthenticationManager newAuthenticationManager() { + XssFilter xssFilter = new AllowXssFilter(); + RuntimeManager runtime = new RuntimeManager(getSettings(), xssFilter, GitBlitSuite.BASEFOLDER).start(); + users = new UserManager(runtime, null).start(); + final Map virtualUsers = new HashMap(); + users.setUserService(new IUserService() { + + @Override + public void setup(IRuntimeManager runtimeManager) { + } + + @Override + public String getCookie(UserModel model) { + return null; + } + + @Override + public UserModel getUserModel(char[] cookie) { + return null; + } + + @Override + public UserModel getUserModel(String username) { + return virtualUsers.get(username); + } + + @Override + public boolean updateUserModel(UserModel model) { + virtualUsers.put(model.username, model); + return true; + } + + @Override + public boolean updateUserModels(Collection models) { + return false; + } + + @Override + public boolean updateUserModel(String username, UserModel model) { + virtualUsers.put(username, model); + return true; + } + + @Override + public boolean deleteUserModel(UserModel model) { + return false; + } + + @Override + public boolean deleteUser(String username) { + return false; + } + + @Override + public List getAllUsernames() { + return null; + } + + @Override + public List getAllUsers() { + return null; + } + + @Override + public List getAllTeamNames() { + return null; + } + + @Override + public List getAllTeams() { + return null; + } + + @Override + public List getTeamNamesForRepositoryRole(String role) { + return null; + } + + @Override + public TeamModel getTeamModel(String teamname) { + return null; + } + + @Override + public boolean updateTeamModel(TeamModel model) { + return false; + } + + @Override + public boolean updateTeamModels(Collection models) { + return false; + } + + @Override + public boolean updateTeamModel(String teamname, TeamModel model) { + return false; + } + + @Override + public boolean deleteTeamModel(TeamModel model) { + return false; + } + + @Override + public boolean deleteTeam(String teamname) { + return false; + } + + @Override + public List getUsernamesForRepositoryRole(String role) { + return null; + } + + @Override + public boolean renameRepositoryRole(String oldRole, + String newRole) { + return false; + } + + @Override + public boolean deleteRepositoryRole(String role) { + return false; + } + + }); + AuthenticationManager auth = new AuthenticationManager(runtime, users).start(); + return auth; + } + + @Test + public void testAuthenticate() throws Exception { + IAuthenticationManager auth = newAuthenticationManager(); + + UserModel user = new UserModel("sunnyjim"); user.password = "password"; users.updateUserModel(user); @@ -65,5 +663,48 @@ public class AuthenticationManagerTest extends GitblitUnitTest { users.updateUserModel(user); assertNull(auth.authenticate(user.username, user.password.toCharArray())); users.deleteUserModel(user); - } + } + + @Test + public void testContenairAuthenticate() throws Exception { + settings.put(Keys.realm.container.autoCreateAccounts, "true"); + settings.put(Keys.realm.container.autoAccounts.displayName, "displayName"); + settings.put(Keys.realm.container.autoAccounts.emailAddress, "emailAddress"); + settings.put(Keys.realm.container.autoAccounts.adminRole, "admin"); + settings.put(Keys.realm.container.autoAccounts.locale, "locale"); + + DummyHttpServletRequest request = new DummyHttpServletRequest(); + request.sessionAttributes.put("displayName", "Sunny Jim"); + request.sessionAttributes.put("emailAddress", "Jim.Sunny@gitblit.com"); + request.sessionAttributes.put("locale", "it"); + + IAuthenticationManager auth = newAuthenticationManager(); + + UserModel user = auth.authenticate(request); + + assertTrue(user.canAdmin); + assertEquals("Sunny Jim", user.displayName); + assertEquals("Jim.Sunny@gitblit.com", user.emailAddress); + assertEquals(Locale.ITALIAN, user.getPreferences().getLocale()); + } + + @Test + public void testContenairAuthenticateEmpty() throws Exception { + settings.put(Keys.realm.container.autoCreateAccounts, "true"); + settings.put(Keys.realm.container.autoAccounts.displayName, "displayName"); + settings.put(Keys.realm.container.autoAccounts.emailAddress, "emailAddress"); + settings.put(Keys.realm.container.autoAccounts.adminRole, "notAdmin"); + + DummyHttpServletRequest request = new DummyHttpServletRequest(); + + IAuthenticationManager auth = newAuthenticationManager(); + + UserModel user = auth.authenticate(request); + + assertFalse(user.canAdmin); + assertEquals("sunnyjim", user.displayName); + assertNull(user.emailAddress); + assertNull(user.getPreferences().getLocale()); + } + } -- 2.39.5