# Valid providers are: | # Valid providers are: | ||||
# | # | ||||
# htpasswd | # htpasswd | ||||
# httpheader | |||||
# ldap | # ldap | ||||
# pam | # pam | ||||
# redmine | # redmine | ||||
# SINCE 1.3.2 | # SINCE 1.3.2 | ||||
realm.htpasswd.userfile = ${baseFolder}/htpasswd | 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. | # Restrict the Salesforce user to members of this org. | ||||
# default: 0 (i.e. do not check the Org ID) | # default: 0 (i.e. do not check the Org ID) | ||||
# | # |
} | } | ||||
public static enum AuthenticationType { | public static enum AuthenticationType { | ||||
PUBLIC_KEY, CREDENTIALS, COOKIE, CERTIFICATE, CONTAINER; | |||||
PUBLIC_KEY, CREDENTIALS, COOKIE, CERTIFICATE, CONTAINER, HTTPHEADER; | |||||
public boolean isStandard() { | public boolean isStandard() { | ||||
return ordinal() <= COOKIE.ordinal(); | return ordinal() <= COOKIE.ordinal(); | ||||
} | } | ||||
public static enum AccountType { | 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) { | public static AccountType fromString(String value) { | ||||
for (AccountType type : AccountType.values()) { | for (AccountType type : AccountType.values()) { |
import java.io.File; | import java.io.File; | ||||
import java.math.BigInteger; | import java.math.BigInteger; | ||||
import javax.servlet.http.HttpServletRequest; | |||||
import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
import com.gitblit.Constants.AccountType; | import com.gitblit.Constants.AccountType; | ||||
import com.gitblit.Constants.Role; | import com.gitblit.Constants.Role; | ||||
import com.gitblit.Constants.AuthenticationType; | |||||
import com.gitblit.IStoredSettings; | import com.gitblit.IStoredSettings; | ||||
import com.gitblit.manager.IRuntimeManager; | import com.gitblit.manager.IRuntimeManager; | ||||
import com.gitblit.manager.IUserManager; | import com.gitblit.manager.IUserManager; | ||||
return serviceName; | return serviceName; | ||||
} | } | ||||
public abstract AuthenticationType getAuthenticationType(); | |||||
protected void setCookie(UserModel user, char [] password) { | protected void setCookie(UserModel user, char [] password) { | ||||
// create a user cookie | // create a user cookie | ||||
if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) { | if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) { | ||||
public abstract void stop(); | 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 UserModel authenticate(String username, char[] password); | ||||
public abstract AccountType getAccountType(); | 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 | * @since 1.0.0 | ||||
*/ | */ | ||||
public abstract boolean supportsCredentialChanges(); | public abstract boolean supportsCredentialChanges(); | ||||
* Returns true if the user's display name can be changed. | * Returns true if the user's display name can be changed. | ||||
* | * | ||||
* @param user | * @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(); | public abstract boolean supportsDisplayNameChanges(); | ||||
* Returns true if the user's email address can be changed. | * Returns true if the user's email address can be changed. | ||||
* | * | ||||
* @param user | * @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(); | public abstract boolean supportsEmailAddressChanges(); | ||||
* Returns true if the user's team memberships can be changed. | * Returns true if the user's team memberships can be changed. | ||||
* | * | ||||
* @param user | * @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(); | public abstract boolean supportsTeamMembershipChanges(); | ||||
super(serviceName); | super(serviceName); | ||||
} | } | ||||
@Override | |||||
public UserModel authenticate(HttpServletRequest httpRequest) { | |||||
return null; | |||||
} | |||||
@Override | |||||
public AuthenticationType getAuthenticationType() { | |||||
return AuthenticationType.CREDENTIALS; | |||||
} | |||||
@Override | @Override | ||||
public void stop() { | public void stop() { | ||||
} | } | ||||
@Override | |||||
public UserModel authenticate(HttpServletRequest httpRequest) { | |||||
return null; | |||||
} | |||||
@Override | @Override | ||||
public UserModel authenticate(String username, char[] password) { | public UserModel authenticate(String username, char[] password) { | ||||
return null; | return null; | ||||
return AccountType.LOCAL; | return AccountType.LOCAL; | ||||
} | } | ||||
@Override | |||||
public AuthenticationType getAuthenticationType() { | |||||
return null; | |||||
} | |||||
@Override | @Override | ||||
public boolean supportsCredentialChanges() { | public boolean supportsCredentialChanges() { | ||||
return true; | return true; |
/* | |||||
* 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; | |||||
} | |||||
} |
import com.gitblit.auth.AuthenticationProvider; | import com.gitblit.auth.AuthenticationProvider; | ||||
import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider; | import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider; | ||||
import com.gitblit.auth.HtpasswdAuthProvider; | import com.gitblit.auth.HtpasswdAuthProvider; | ||||
import com.gitblit.auth.HttpHeaderAuthProvider; | |||||
import com.gitblit.auth.LdapAuthProvider; | import com.gitblit.auth.LdapAuthProvider; | ||||
import com.gitblit.auth.PAMAuthProvider; | import com.gitblit.auth.PAMAuthProvider; | ||||
import com.gitblit.auth.RedmineAuthProvider; | import com.gitblit.auth.RedmineAuthProvider; | ||||
// map of shortcut provider names | // map of shortcut provider names | ||||
providerNames = new HashMap<String, Class<? extends AuthenticationProvider>>(); | providerNames = new HashMap<String, Class<? extends AuthenticationProvider>>(); | ||||
providerNames.put("htpasswd", HtpasswdAuthProvider.class); | providerNames.put("htpasswd", HtpasswdAuthProvider.class); | ||||
providerNames.put("httpheader", HttpHeaderAuthProvider.class); | |||||
providerNames.put("ldap", LdapAuthProvider.class); | providerNames.put("ldap", LdapAuthProvider.class); | ||||
providerNames.put("pam", PAMAuthProvider.class); | providerNames.put("pam", PAMAuthProvider.class); | ||||
providerNames.put("redmine", RedmineAuthProvider.class); | providerNames.put("redmine", RedmineAuthProvider.class); | ||||
} | } | ||||
/** | /** | ||||
* 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. | * Authentication by X509Certificate is tried first and then by cookie. | ||||
* | * | ||||
/** | /** | ||||
* Authenticate a user based on HTTP request parameters. | * 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. | * and finally BASIC header. | ||||
* | * | ||||
* @param httpRequest | * @param httpRequest | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// 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; | return null; | ||||
} | } | ||||