Mercurial > hg > tc-symbol-server
changeset 36:53abede95333 auth
stop using *auh prefixes in url's to switch between auth schemes
author | Evgeniy.Koshkin |
---|---|
date | Tue, 27 Aug 2013 16:19:31 +0400 |
parents | 2d2f54daf202 |
children | 7e971d72b49c |
files | common/src/jetbrains/buildServer/symbols/SymbolsConstants.java server/resources/editSymbolsBuildFeatureParams.jsp server/resources/symbolServerSettings.jsp server/src/jetbrains/buildServer/symbols/DownloadSourcesController.java server/src/jetbrains/buildServer/symbols/DownloadSymbolsController.java server/src/jetbrains/buildServer/symbols/IndexSymbolsBuildFeature.java server/src/jetbrains/buildServer/symbols/SymbolServerSettingsTab.java server/src/jetbrains/buildServer/symbols/SymbolsIndexerParametersPreprocessor.java |
diffstat | 8 files changed, 112 insertions(+), 132 deletions(-) [+] |
line wrap: on
line diff
--- a/common/src/jetbrains/buildServer/symbols/SymbolsConstants.java Fri Aug 23 16:27:59 2013 +0400 +++ b/common/src/jetbrains/buildServer/symbols/SymbolsConstants.java Tue Aug 27 16:19:31 2013 +0400 @@ -6,13 +6,9 @@ public class SymbolsConstants { public static final String BUILD_FEATURE_TYPE = "symbol-indexer"; - public static final String SOURCES_AUTH_REQUIRED_PARAM_NAME = "symbols.sources-auth-required"; public static final String SOURCES_SERVER_URL_PARAM_NAME = "symbols.sources-server-url"; public static final String SERVER_OWN_URL_PARAM_NAME = "symbols.server-own-url"; - public static final String APP_SYMBOLS = "app/symbols/"; - public static final String APP_SOURCES = "app/sources/"; - - public static final String APP_SYMBOLS_INTERNAL = "app/symbols-internal/"; - public static final String APP_SOURCES_INTERNAL = "app/sources-internal/"; + public static final String APP_SYMBOLS = "/app/symbols/"; + public static final String APP_SOURCES = "/app/sources/"; }
--- a/server/resources/editSymbolsBuildFeatureParams.jsp Fri Aug 23 16:27:59 2013 +0400 +++ b/server/resources/editSymbolsBuildFeatureParams.jsp Tue Aug 27 16:19:31 2013 +0400 @@ -1,18 +1,9 @@ <%@ include file="/include-internal.jsp"%> -<jsp:useBean id="isGuestEnabled" scope="request" type="java.lang.Boolean"/> - <table class="runnerFormTable"> <tr> <td colspan="2"> <em>Symbols and sources indexing will be performed for all symbol files (.pdb) appeared among build artifacts.</em> </td> </tr> - <tr> - <th>Sources Access:</th> - <td> - <props:checkboxProperty name="symbols.sources-auth-required"/> - <label for="symbols.sources-auth-required">Grand access to the sources to authenticated users only.</label> - </td> - </tr> </table> \ No newline at end of file
--- a/server/resources/symbolServerSettings.jsp Fri Aug 23 16:27:59 2013 +0400 +++ b/server/resources/symbolServerSettings.jsp Tue Aug 27 16:19:31 2013 +0400 @@ -1,44 +1,16 @@ <%@ include file="/include-internal.jsp"%> <jsp:useBean id="pageUrl" type="java.lang.String" scope="request"/> -<jsp:useBean id="isGuestEnabled" scope="request" type="java.lang.Boolean"/> -<jsp:useBean id="publicUrl" scope="request" type="java.lang.String" /> -<jsp:useBean id="privateUrl" scope="request" type="java.lang.String" /> +<jsp:useBean id="appUrl" scope="request" type="java.lang.String" /> <jsp:useBean id="actualServerUrl" scope="request" type="java.lang.String" /> <table class="runnerFormTable"> <tr> - <td colspan="2"> - <em>Use this URL in Visual Studio and WinDbg settings.</em> - </td> - </tr> - <tr> - <th>Authenticated URL:</th> - <td> - <c:set var="url"><c:url value="${actualServerUrl}${privateUrl}"/></c:set> - <div><a href="${url}">${url}</a></div> - <span class="smallNote">Access to the url requires HTTP authentication</span> - </td> - </tr> - <tr> - <th>Public URL:</th> + <th>Symbol Server URL:</th> <td> - <c:choose> - <c:when test="${not isGuestEnabled}"> - <div>Not available.</div> - <span class="smallNote"> - Guest user is disabled. - </span> - <span class="smallNote"> - You need to enable guest user login in TeamCity <a href="<c:url value="/admin/admin.html?item=auth"/>">Authentication Settings</a> for public url to work. - </span> - </c:when> - <c:otherwise> - <c:set var="url"><c:url value="${actualServerUrl}${publicUrl}"/></c:set> - <div><a href="${url}">${url}</a></div> - <span class="smallNote">No authentication is required.</span> - </c:otherwise> - </c:choose> + <c:set var="url"><c:url value="${actualServerUrl}${appUrl}"/></c:set> + <div><a href="${url}">${url}</a></div> + <span class="smallNote">Use this URL in Visual Studio and WinDbg settings.</span> </td> </tr> </table> \ No newline at end of file
--- a/server/src/jetbrains/buildServer/symbols/DownloadSourcesController.java Fri Aug 23 16:27:59 2013 +0400 +++ b/server/src/jetbrains/buildServer/symbols/DownloadSourcesController.java Tue Aug 27 16:19:31 2013 +0400 @@ -16,8 +16,15 @@ package jetbrains.buildServer.symbols; +import jetbrains.buildServer.controllers.AuthorizationInterceptor; import jetbrains.buildServer.controllers.BaseController; +import jetbrains.buildServer.controllers.interceptors.auth.HttpAuthenticationManager; +import jetbrains.buildServer.controllers.interceptors.auth.HttpAuthenticationResult; import jetbrains.buildServer.serverSide.SBuildServer; +import jetbrains.buildServer.serverSide.auth.Permission; +import jetbrains.buildServer.serverSide.auth.ServerPrincipal; +import jetbrains.buildServer.users.SUser; +import jetbrains.buildServer.users.UserModel; import jetbrains.buildServer.web.openapi.WebControllerManager; import jetbrains.buildServer.web.util.WebUtil; import org.apache.log4j.Logger; @@ -35,12 +42,22 @@ public class DownloadSourcesController extends BaseController { private static final String VALID_URL_PATTERN = ".*/builds/id-\\d*/sources/.*"; - private static final Logger LOG = Logger.getLogger(DownloadSourcesController.class); - public DownloadSourcesController(@NotNull SBuildServer server, @NotNull WebControllerManager controllerManager) { + @NotNull private final UserModel myUserModel; + @NotNull private final HttpAuthenticationManager myAuthManager; + + public DownloadSourcesController(@NotNull SBuildServer server, + @NotNull WebControllerManager webManager, + @NotNull AuthorizationInterceptor authInterceptor, + @NotNull UserModel userModel, + @NotNull HttpAuthenticationManager authManager) { super(server); - controllerManager.registerController(SymbolsConstants.APP_SOURCES + "**", this); + myUserModel = userModel; + myAuthManager = authManager; + final String path = SymbolsConstants.APP_SOURCES + "**"; + webManager.registerController(path, this); + authInterceptor.addPathNotRequiringAuth(path); } @Nullable @@ -51,6 +68,28 @@ WebUtil.notFound(request, response, "Url is invalid", null); return null; } + + final HttpAuthenticationResult authResult = myAuthManager.processAuthenticationRequest(request, response); + switch (authResult.getType()) { + case NOT_APPLICABLE: + response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE, "TODO"); //TODO error message + return null; + case UNAUTHENTICATED: + return null; + } + + final ServerPrincipal principal = authResult.getPrincipal(); + final SUser user = myUserModel.findUserAccount(principal.getRealm(), principal.getName()); + if(user == null){ + response.sendError(HttpServletResponse.SC_FORBIDDEN, "TODO"); //TODO error message + return null; + } + + if (!user.isPermissionGrantedGlobally(Permission.VIEW_FILE_CONTENT)) { //TODO: check permissions locally (for particular project) + response.sendError(HttpServletResponse.SC_FORBIDDEN, "You have no permissions to view source files content."); + return null; + } + String restMethodUrl = requestURI.replace("/builds/id-", "/builds/id:").replace("/app/sources/", "/app/rest/"); final String contextPath = request.getContextPath(); if(restMethodUrl.startsWith(contextPath)){
--- a/server/src/jetbrains/buildServer/symbols/DownloadSymbolsController.java Fri Aug 23 16:27:59 2013 +0400 +++ b/server/src/jetbrains/buildServer/symbols/DownloadSymbolsController.java Tue Aug 27 16:19:31 2013 +0400 @@ -2,25 +2,26 @@ import jetbrains.buildServer.controllers.AuthorizationInterceptor; import jetbrains.buildServer.controllers.BaseController; +import jetbrains.buildServer.controllers.interceptors.auth.HttpAuthenticationManager; +import jetbrains.buildServer.controllers.interceptors.auth.HttpAuthenticationResult; import jetbrains.buildServer.serverSide.SBuild; import jetbrains.buildServer.serverSide.SBuildServer; +import jetbrains.buildServer.serverSide.SecurityContextEx; import jetbrains.buildServer.serverSide.artifacts.BuildArtifact; import jetbrains.buildServer.serverSide.artifacts.BuildArtifactsViewMode; import jetbrains.buildServer.serverSide.auth.Permission; +import jetbrains.buildServer.serverSide.auth.ServerPrincipal; import jetbrains.buildServer.serverSide.metadata.BuildMetadataEntry; import jetbrains.buildServer.serverSide.metadata.MetadataStorage; import jetbrains.buildServer.users.SUser; import jetbrains.buildServer.users.UserModel; import jetbrains.buildServer.util.FileUtil; import jetbrains.buildServer.web.openapi.WebControllerManager; -import jetbrains.buildServer.web.util.SessionUser; import jetbrains.buildServer.web.util.WebUtil; import org.apache.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.springframework.web.servlet.ModelAndView; - -import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedOutputStream; @@ -33,39 +34,39 @@ */ public class DownloadSymbolsController extends BaseController { - private static final String APP_SYMBOLS = "/" + SymbolsConstants.APP_SYMBOLS; - private static final String APP_SYMBOLS_INTERNAL = "/" + SymbolsConstants.APP_SYMBOLS_INTERNAL; - private static final String COMPRESSED_FILE_EXTENSION = "pd_"; private static final String FILE_POINTER_FILE_EXTENSION = "ptr"; private static final Logger LOG = Logger.getLogger(DownloadSymbolsController.class); - @NotNull - private final UserModel myUserModel; + @NotNull private final UserModel myUserModel; + @NotNull private final SecurityContextEx mySecurityContext; @NotNull private final MetadataStorage myBuildMetadataStorage; + @NotNull private final HttpAuthenticationManager myAuthManager; public DownloadSymbolsController(@NotNull SBuildServer server, @NotNull WebControllerManager controllerManager, @NotNull AuthorizationInterceptor authInterceptor, + @NotNull SecurityContextEx securityContext, + @NotNull HttpAuthenticationManager authManager, @NotNull UserModel userModel, @NotNull MetadataStorage buildMetadataStorage) { super(server); + mySecurityContext = securityContext; myUserModel = userModel; myBuildMetadataStorage = buildMetadataStorage; - final String path = APP_SYMBOLS + "**"; + myAuthManager = authManager; + final String path = SymbolsConstants.APP_SYMBOLS + "**"; controllerManager.registerController(path, this); authInterceptor.addPathNotRequiringAuth(path); - final String internalPath = APP_SYMBOLS_INTERNAL + "**"; - controllerManager.registerController(internalPath, this); } @Nullable @Override - protected ModelAndView doHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws Exception { + protected ModelAndView doHandle(final @NotNull HttpServletRequest request, final @NotNull HttpServletResponse response) throws Exception { final String requestURI = request.getRequestURI(); - if(requestURI.endsWith(APP_SYMBOLS)){ + if(requestURI.endsWith(SymbolsConstants.APP_SYMBOLS)){ response.sendError(HttpServletResponse.SC_OK, "TeamCity Symbol Server available"); return null; } @@ -79,53 +80,58 @@ return null; } - final SUser user = SessionUser.getUser(request); - if (user != null && !user.isPermissionGrantedGlobally(Permission.VIEW_BUILD_RUNTIME_DATA)) { - response.sendError(HttpServletResponse.SC_FORBIDDEN, "You have no permissions to download PDB files."); - return null; - } else { - if (!myServer.getLoginConfiguration().isGuestLoginAllowed() || !myUserModel.getGuestUser().isPermissionGrantedGlobally(Permission.VIEW_BUILD_RUNTIME_DATA)) { - - String authRequiredUrl; - final String contextPath = request.getContextPath(); - if(requestURI.startsWith(contextPath)) - authRequiredUrl = WebUtil.HTTP_AUTH_PREFIX + requestURI.substring(contextPath.length() + 1); - else - authRequiredUrl = WebUtil.HTTP_AUTH_PREFIX + requestURI.substring(1); - - authRequiredUrl = authRequiredUrl.replace(APP_SYMBOLS, APP_SYMBOLS_INTERNAL); - - LOG.debug("Unauthorized access to PDB files is denied. Forwarding request to auth-required URL " + authRequiredUrl); - final RequestDispatcher dispatcher = request.getRequestDispatcher(authRequiredUrl); - dispatcher.forward(request, response); + final HttpAuthenticationResult authResult = myAuthManager.processAuthenticationRequest(request, response); + switch (authResult.getType()) { + case NOT_APPLICABLE: + response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE, "TODO"); //TODO error message return null; - } + case UNAUTHENTICATED: + return null; } - final String valuableUriPart = requestURI.substring(requestURI.indexOf(APP_SYMBOLS) + APP_SYMBOLS.length()); - final int firstDelimiterPosition = valuableUriPart.indexOf('/'); - final String fileName = valuableUriPart.substring(0, firstDelimiterPosition); - final String signature = valuableUriPart.substring(firstDelimiterPosition + 1, valuableUriPart.indexOf('/', firstDelimiterPosition + 1)); - final String guid = signature.substring(0, signature.length() - 1); //last symbol is PEDebugType - LOG.debug(String.format("Symbol file requested. File name: %s. Guid: %s.", fileName, guid)); - - final BuildArtifact buildArtifact = findArtifact(guid, fileName); - if(buildArtifact == null){ - WebUtil.notFound(request, response, "Symbol file not found", null); - LOG.debug(String.format("Symbol file not found. File name: %s. Guid: %s.", fileName, guid)); + final ServerPrincipal principal = authResult.getPrincipal(); + final SUser user = myUserModel.findUserAccount(principal.getRealm(), principal.getName()); + if(user == null){ + response.sendError(HttpServletResponse.SC_FORBIDDEN, "TODO"); //TODO error message + return null; + } + if (!user.isPermissionGrantedGlobally(Permission.VIEW_BUILD_RUNTIME_DATA)) { //TODO: check permissions locally (for particular project) + response.sendError(HttpServletResponse.SC_FORBIDDEN, "You have no permissions to download PDB files."); return null; } - BufferedOutputStream output = new BufferedOutputStream(response.getOutputStream()); try { - InputStream input = buildArtifact.getInputStream(); - try { - FileUtil.copyStreams(input, output); - } finally { - FileUtil.close(input); - } - } finally { - FileUtil.close(output); + mySecurityContext.runAs(user, new SecurityContextEx.RunAsAction() { + public void run() throws Throwable { + final String valuableUriPart = requestURI.substring(requestURI.indexOf(SymbolsConstants.APP_SYMBOLS) + SymbolsConstants.APP_SYMBOLS.length()); + final int firstDelimiterPosition = valuableUriPart.indexOf('/'); + final String fileName = valuableUriPart.substring(0, firstDelimiterPosition); + final String signature = valuableUriPart.substring(firstDelimiterPosition + 1, valuableUriPart.indexOf('/', firstDelimiterPosition + 1)); + final String guid = signature.substring(0, signature.length() - 1); //last symbol is PEDebugType + LOG.debug(String.format("Symbol file requested. File name: %s. Guid: %s.", fileName, guid)); + + final BuildArtifact buildArtifact = findArtifact(guid, fileName); + if(buildArtifact == null){ + WebUtil.notFound(request, response, "Symbol file not found", null); + LOG.debug(String.format("Symbol file not found. File name: %s. Guid: %s.", fileName, guid)); + return; + } + + BufferedOutputStream output = new BufferedOutputStream(response.getOutputStream()); + try { + InputStream input = buildArtifact.getInputStream(); + try { + FileUtil.copyStreams(input, output); + } finally { + FileUtil.close(input); + } + } finally { + FileUtil.close(output); + } + } + }); + } catch (Throwable throwable) { + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, throwable.getMessage()); } return null;
--- a/server/src/jetbrains/buildServer/symbols/IndexSymbolsBuildFeature.java Fri Aug 23 16:27:59 2013 +0400 +++ b/server/src/jetbrains/buildServer/symbols/IndexSymbolsBuildFeature.java Tue Aug 27 16:19:31 2013 +0400 @@ -2,17 +2,14 @@ import jetbrains.buildServer.controllers.BaseController; import jetbrains.buildServer.serverSide.BuildFeature; -import jetbrains.buildServer.serverSide.impl.ServerSettings; import jetbrains.buildServer.web.openapi.PluginDescriptor; import jetbrains.buildServer.web.openapi.WebControllerManager; -import jetbrains.buildServer.web.util.WebUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.util.Map; /** * @author Evgeniy.Koshkin @@ -21,18 +18,14 @@ private String myEditParametersUrl; - public IndexSymbolsBuildFeature(final PluginDescriptor pluginDescriptor, final WebControllerManager web, final ServerSettings serverSettings) { + public IndexSymbolsBuildFeature(final PluginDescriptor pluginDescriptor, final WebControllerManager web) { final String jsp = pluginDescriptor.getPluginResourcesPath("editSymbolsBuildFeatureParams.jsp"); final String html = pluginDescriptor.getPluginResourcesPath("symbolIndexerSettings.html"); web.registerController(html, new BaseController() { @Override protected ModelAndView doHandle(final HttpServletRequest request, final HttpServletResponse response) throws Exception { - final ModelAndView modelAndView = new ModelAndView(jsp); - modelAndView.getModel().put("isGuestEnabled", serverSettings.isGuestLoginAllowed()); - modelAndView.getModel().put("actualServerUrl", WebUtil.getRootUrl(request)); - modelAndView.getModel().put("publicFeedUrl", WebUtil.GUEST_AUTH_PREFIX + SymbolsConstants.APP_SYMBOLS); - return modelAndView; + return new ModelAndView(jsp); } }); @@ -61,12 +54,4 @@ public String getEditParametersUrl() { return myEditParametersUrl; } - - @NotNull - @Override - public String describeParameters(@NotNull Map<String, String> params) { - return Boolean.parseBoolean(params.get(SymbolsConstants.SOURCES_AUTH_REQUIRED_PARAM_NAME)) - ? "Access to the indexed sources requires HTTP authentication." - : "No authentication is required to retrieve indexed sources"; - } }
--- a/server/src/jetbrains/buildServer/symbols/SymbolServerSettingsTab.java Fri Aug 23 16:27:59 2013 +0400 +++ b/server/src/jetbrains/buildServer/symbols/SymbolServerSettingsTab.java Tue Aug 27 16:19:31 2013 +0400 @@ -19,7 +19,6 @@ import jetbrains.buildServer.serverSide.auth.AuthUtil; import jetbrains.buildServer.serverSide.auth.Permission; import jetbrains.buildServer.serverSide.auth.SecurityContext; -import jetbrains.buildServer.serverSide.impl.ServerSettings; import jetbrains.buildServer.web.openapi.PagePlaces; import jetbrains.buildServer.web.openapi.PlaceId; import jetbrains.buildServer.web.openapi.PluginDescriptor; @@ -37,11 +36,9 @@ private static final String TAB_ID = "sourceServerSettingsTab"; - @NotNull private final ServerSettings myServerSettings; @NotNull private final SecurityContext mySecurityContext; public SymbolServerSettingsTab(@NotNull final PagePlaces pagePlaces, - @NotNull final ServerSettings serverSettings, @NotNull final SecurityContext context, @NotNull final PluginDescriptor descriptor) { super(pagePlaces, @@ -49,7 +46,6 @@ TAB_ID, descriptor.getPluginResourcesPath("symbolServerSettings.jsp"), "Symbol Server"); - myServerSettings = serverSettings; mySecurityContext = context; register(); } @@ -67,10 +63,8 @@ @Override public void fillModel(@NotNull Map<String, Object> model, @NotNull HttpServletRequest request) { super.fillModel(model, request); - model.put("isGuestEnabled", myServerSettings.isGuestLoginAllowed()); model.put("actualServerUrl", WebUtil.getRootUrl(request)); - model.put("publicUrl", WebUtil.GUEST_AUTH_PREFIX + SymbolsConstants.APP_SYMBOLS); - model.put("privateUrl", WebUtil.HTTP_AUTH_PREFIX + SymbolsConstants.APP_SYMBOLS); + model.put("appUrl", SymbolsConstants.APP_SYMBOLS); } private boolean hasAccess() {
--- a/server/src/jetbrains/buildServer/symbols/SymbolsIndexerParametersPreprocessor.java Fri Aug 23 16:27:59 2013 +0400 +++ b/server/src/jetbrains/buildServer/symbols/SymbolsIndexerParametersPreprocessor.java Tue Aug 27 16:19:31 2013 +0400 @@ -18,7 +18,6 @@ import jetbrains.buildServer.RootUrlHolder; import jetbrains.buildServer.serverSide.*; -import jetbrains.buildServer.web.util.WebUtil; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -40,13 +39,11 @@ final Collection<SBuildFeatureDescriptor> buildFeatures = buildType.getResolvedSettings().getBuildFeatures(); for(SBuildFeatureDescriptor buildFeature : buildFeatures){ if(!buildFeature.getId().equals(SymbolsConstants.BUILD_FEATURE_TYPE)) continue; - boolean isAuthRequiredToGetSources = buildFeature.getParameters().containsKey(SymbolsConstants.SOURCES_AUTH_REQUIRED_PARAM_NAME); String serverOwnUrl = context.getSharedParameters().get(SymbolsConstants.SERVER_OWN_URL_PARAM_NAME); if(serverOwnUrl == null){ serverOwnUrl = myRootUrlHolder.getRootUrl(); } - final String authPrefix = isAuthRequiredToGetSources ? WebUtil.HTTP_AUTH_PREFIX : WebUtil.GUEST_AUTH_PREFIX; - final String sourceServerUrl = String.format("%s%s%s", serverOwnUrl, authPrefix, SymbolsConstants.APP_SOURCES); + final String sourceServerUrl = String.format("%s%s", serverOwnUrl, SymbolsConstants.APP_SOURCES); context.addSharedParameter(SymbolsConstants.SOURCES_SERVER_URL_PARAM_NAME, sourceServerUrl); } }