src/main/distrib/data/defaults.properties | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/Constants.java | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/auth/AuthenticationProvider.java | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/auth/HttpHeaderAuthProvider.java | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/manager/AuthenticationManager.java | ●●●●● patch | view | raw | blame | history |
src/main/distrib/data/defaults.properties
@@ -817,6 +817,7 @@ # Valid providers are: # # htpasswd # httpheader # ldap # pam # redmine @@ -1739,6 +1740,42 @@ # SINCE 1.3.2 realm.htpasswd.userfile = ${baseFolder}/htpasswd # The name of the HTTP header containing the user name to trust as authenticated # default: none # # WARNING: only use this mechanism if your requests are coming from a trusted # and secure source such as a self managed reverse proxy! # # RESTART REQUIRED # SINCE 1.7.2 realm.httpheader.userheader = # The name of the HTTP header containing the team names of which the user is a member. # If this is defined, then only groups from the headers will be available, whereas # if this remains undefined, then local groups will be used. # # This setting requires that you have configured realm.httpheader.userheader. # # default: none # # RESTART REQUIRED # SINCE 1.7.2 realm.httpheader.teamheader = # The regular expression pattern used to separate team names in the team header value # default: , # # This setting requires that you have configured realm.httpheader.teamheader # # RESTART REQUIRED # SINCE 1.7.2 realm.httpheader.teamseparator = , # Auto-creates user accounts when successfully authenticated based on HTTP headers. # # SINCE 1.7.2 realm.httpheader.autoCreateAccounts = false # Restrict the Salesforce user to members of this org. # default: 0 (i.e. do not check the Org ID) # src/main/java/com/gitblit/Constants.java
@@ -574,7 +574,7 @@ } public static enum AuthenticationType { PUBLIC_KEY, CREDENTIALS, COOKIE, CERTIFICATE, CONTAINER; PUBLIC_KEY, CREDENTIALS, COOKIE, CERTIFICATE, CONTAINER, HTTPHEADER; public boolean isStandard() { return ordinal() <= COOKIE.ordinal(); @@ -582,7 +582,7 @@ } public static enum AccountType { LOCAL, EXTERNAL, CONTAINER, LDAP, REDMINE, SALESFORCE, WINDOWS, PAM, HTPASSWD; LOCAL, EXTERNAL, CONTAINER, LDAP, REDMINE, SALESFORCE, WINDOWS, PAM, HTPASSWD, HTTPHEADER; public static AccountType fromString(String value) { for (AccountType type : AccountType.values()) { src/main/java/com/gitblit/auth/AuthenticationProvider.java
@@ -18,11 +18,14 @@ import java.io.File; import java.math.BigInteger; import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.gitblit.Constants.AccountType; import com.gitblit.Constants.Role; import com.gitblit.Constants.AuthenticationType; import com.gitblit.IStoredSettings; import com.gitblit.manager.IRuntimeManager; import com.gitblit.manager.IUserManager; @@ -73,6 +76,8 @@ return serviceName; } public abstract AuthenticationType getAuthenticationType(); protected void setCookie(UserModel user, char [] password) { // create a user cookie if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) { @@ -116,14 +121,32 @@ public abstract void stop(); /** * Used to handle requests for requests for pages requiring authentication. * This allows authentication to occur based on the contents of the request * itself. * * @param httpRequest * @return */ public abstract UserModel authenticate(HttpServletRequest httpRequest); /** * Used to authentication user/password credentials, both for login form * and HTTP Basic authentication processing. * * @param username * @param password * @return */ public abstract UserModel authenticate(String username, char[] password); public abstract AccountType getAccountType(); /** * Does the user service support changes to credentials? * Returns true if the users's credentials can be changed. * * @return true or false * @return true if the authentication provider supports credential changes * @since 1.0.0 */ public abstract boolean supportsCredentialChanges(); @@ -132,7 +155,7 @@ * Returns true if the user's display name can be changed. * * @param user * @return true if the user service supports display name changes * @return true if the authentication provider supports display name changes */ public abstract boolean supportsDisplayNameChanges(); @@ -140,7 +163,7 @@ * Returns true if the user's email address can be changed. * * @param user * @return true if the user service supports email address changes * @return true if the authentication provider supports email address changes */ public abstract boolean supportsEmailAddressChanges(); @@ -148,7 +171,7 @@ * Returns true if the user's team memberships can be changed. * * @param user * @return true if the user service supports team membership changes * @return true if the authentication provider supports team membership changes */ public abstract boolean supportsTeamMembershipChanges(); @@ -181,6 +204,16 @@ } @Override public UserModel authenticate(HttpServletRequest httpRequest) { return null; } @Override public AuthenticationType getAuthenticationType() { return AuthenticationType.CREDENTIALS; } @Override public void stop() { } @@ -203,6 +236,11 @@ } @Override public UserModel authenticate(HttpServletRequest httpRequest) { return null; } @Override public UserModel authenticate(String username, char[] password) { return null; } @@ -213,6 +251,11 @@ } @Override public AuthenticationType getAuthenticationType() { return null; } @Override public boolean supportsCredentialChanges() { return true; } src/main/java/com/gitblit/auth/HttpHeaderAuthProvider.java
New file @@ -0,0 +1,161 @@ /* * Copyright 2015 gitblit.com. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gitblit.auth; import java.util.HashSet; import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.gitblit.Constants; import com.gitblit.Constants.AccountType; import com.gitblit.Constants.AuthenticationType; import com.gitblit.Constants.Role; import com.gitblit.Keys; import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; import com.gitblit.utils.StringUtils; public class HttpHeaderAuthProvider extends AuthenticationProvider { protected final Logger logger = LoggerFactory.getLogger(getClass()); protected String userHeaderName; protected String teamHeaderName; protected String teamHeaderSeparator; public HttpHeaderAuthProvider() { super("httpheader"); } @Override public void setup() { // Load HTTP header configuration userHeaderName = settings.getString(Keys.realm.httpheader.userheader, null); teamHeaderName = settings.getString(Keys.realm.httpheader.teamheader, null); teamHeaderSeparator = settings.getString(Keys.realm.httpheader.teamseparator, ","); if (StringUtils.isEmpty(userHeaderName)) { logger.warn("HTTP Header authentication is enabled, but no header is not defined in " + Keys.realm.httpheader.userheader); } } @Override public void stop() {} @Override public UserModel authenticate(HttpServletRequest httpRequest) { // Try to authenticate using custom HTTP header if user header is defined if (!StringUtils.isEmpty(userHeaderName)) { String headerUserName = httpRequest.getHeader(userHeaderName); if (!StringUtils.isEmpty(headerUserName) && !userManager.isInternalAccount(headerUserName)) { // We have a user, try to load team names as well Set<TeamModel> userTeams = new HashSet<>(); if (!StringUtils.isEmpty(teamHeaderName)) { String headerTeamValue = httpRequest.getHeader(teamHeaderName); if (!StringUtils.isEmpty(headerTeamValue)) { String[] headerTeamNames = headerTeamValue.split(teamHeaderSeparator); for (String teamName : headerTeamNames) { teamName = teamName.trim(); if (!StringUtils.isEmpty(teamName)) { TeamModel team = userManager.getTeamModel(teamName); if (null == team) { // Create teams here so they can marked with the correct AccountType team = new TeamModel(teamName); team.accountType = AccountType.HTTPHEADER; updateTeam(team); } userTeams.add(team); } } } } UserModel user = userManager.getUserModel(headerUserName); if (user != null) { // If team header is provided in request, reset all team memberships, even if resetting to empty set if (!StringUtils.isEmpty(teamHeaderName)) { user.teams.clear(); user.teams.addAll(userTeams); } updateUser(user); return user; } else if (settings.getBoolean(Keys.realm.httpheader.autoCreateAccounts, false)) { // auto-create user from HTTP header user = new UserModel(headerUserName.toLowerCase()); user.displayName = headerUserName; user.password = Constants.EXTERNAL_ACCOUNT; user.accountType = AccountType.HTTPHEADER; user.teams.addAll(userTeams); updateUser(user); return user; } } } return null; } @Override public UserModel authenticate(String username, char[] password){ // Username/password is not supported for HTTP header authentication return null; } @Override public AccountType getAccountType() { return AccountType.HTTPHEADER; } @Override public AuthenticationType getAuthenticationType() { return AuthenticationType.HTTPHEADER; } @Override public boolean supportsCredentialChanges() { return false; } @Override public boolean supportsDisplayNameChanges() { return false; } @Override public boolean supportsEmailAddressChanges() { return false; } @Override public boolean supportsTeamMembershipChanges() { return StringUtils.isEmpty(teamHeaderName); } @Override public boolean supportsRoleChanges(UserModel user, Role role) { return true; } @Override public boolean supportsRoleChanges(TeamModel team, Role role) { return true; } } src/main/java/com/gitblit/manager/AuthenticationManager.java
@@ -41,6 +41,7 @@ import com.gitblit.auth.AuthenticationProvider; import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider; import com.gitblit.auth.HtpasswdAuthProvider; import com.gitblit.auth.HttpHeaderAuthProvider; import com.gitblit.auth.LdapAuthProvider; import com.gitblit.auth.PAMAuthProvider; import com.gitblit.auth.RedmineAuthProvider; @@ -92,6 +93,7 @@ // map of shortcut provider names providerNames = new HashMap<String, Class<? extends AuthenticationProvider>>(); providerNames.put("htpasswd", HtpasswdAuthProvider.class); providerNames.put("httpheader", HttpHeaderAuthProvider.class); providerNames.put("ldap", LdapAuthProvider.class); providerNames.put("pam", PAMAuthProvider.class); providerNames.put("redmine", RedmineAuthProvider.class); @@ -170,7 +172,11 @@ } /** * Authenticate a user based on HTTP request parameters. * Used to handle authentication for page requests. * * This allows authentication to occur based on the contents of the request * itself. If no configured @{AuthenticationProvider}s authenticate succesffully, * a request for login will be shown. * * Authentication by X509Certificate is tried first and then by cookie. * @@ -185,7 +191,7 @@ /** * Authenticate a user based on HTTP request parameters. * * Authentication by servlet container principal, X509Certificate, cookie, * Authentication by custom HTTP header, servlet container principal, X509Certificate, cookie, * and finally BASIC header. * * @param httpRequest @@ -319,6 +325,18 @@ } } } // Check each configured AuthenticationProvider for (AuthenticationProvider ap : authenticationProviders) { UserModel authedUser = ap.authenticate(httpRequest); if (null != authedUser) { flagRequest(httpRequest, ap.getAuthenticationType(), authedUser.username); logger.debug(MessageFormat.format("{0} authenticated by {1} from {2} for {3}", authedUser.username, ap.getServiceName(), httpRequest.getRemoteAddr(), httpRequest.getPathInfo())); return validateAuthentication(authedUser, ap.getAuthenticationType()); } } return null; }