From: James Moger Date: Tue, 25 Oct 2011 21:23:47 +0000 (-0400) Subject: Documentation. Changed status RPC protection. Status tab for Manager. X-Git-Tag: v0.7.0~49 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=486ee115abb831b2ec78be6777fb1bca9e931df0;p=gitblit.git Documentation. Changed status RPC protection. Status tab for Manager. --- diff --git a/distrib/gitblit.properties b/distrib/gitblit.properties index 2d48da6e..ad1698e9 100644 --- a/distrib/gitblit.properties +++ b/distrib/gitblit.properties @@ -184,7 +184,7 @@ web.mountParameters = true # to preemptively replace '/' with '*' or '!' for url string parameters. # # -# +# # # SINCE 0.5.2 web.forwardSlashCharacter = / diff --git a/docs/01_setup.mkd b/docs/01_setup.mkd index b2c5b2f8..0939d5a2 100644 --- a/docs/01_setup.mkd +++ b/docs/01_setup.mkd @@ -159,7 +159,7 @@ Usernames must be unique and are case-insensitive. Whitespace is illegal. #### Passwords -User passwords are CASE-SENSITIVE and may be *plain* or *md5* formatted (see `gitblit.properties` -> *realm.passwordStorage*). +User passwords are CASE-SENSITIVE and may be *plain*, *md5*, or *combined-md5* formatted (see `gitblit.properties` -> *realm.passwordStorage*). #### User Roles There are two actual *roles* in Gitblit: *#admin*, which grants administrative powers to that user, and *#notfederated*, which prevents an account from being pulled by another Gitblit instance. Administrators automatically have access to all repositories. All other *roles* are repository names. If a repository is access-restricted, the user must have the repository's name within his/her roles to bypass the access restriction. This is how users are granted access to a restricted repository. diff --git a/docs/02_rpc.mkd b/docs/02_rpc.mkd index 82655085..6384862a 100644 --- a/docs/02_rpc.mkd +++ b/docs/02_rpc.mkd @@ -14,9 +14,11 @@ The Gitblit RPC mechanism, like the Gitblit JGit servlet, syndication/feed servl ### RPC Requests - + + + @@ -30,6 +32,7 @@ The Gitblit RPC mechanism, like the Gitblit JGit servlet, syndication/feed servl + @@ -51,6 +54,9 @@ The Gitblit RPC mechanism, like the Gitblit JGit servlet, syndication/feed servl [Gitblit Manager](http://code.google.com/p/gitblit/downloads/detail?name=%MANAGER%) is an example Java/Swing application that allows remote administration of a Gitblit server. This application exercises many, but not all, methods from the utility class `com.gitblit.utils.RpcUtils`. +**NOTE:** +Gitblit Manager stores your login credentials **INSECURELY** in homedir/.gitblit/config. + ### EGit "Import from Gitblit" Feature (Planning) One obvious goal of a Gitblit RPC mechanism would be to have an EGit Feature that allows authentication and enumeration of Gitblit repositories from the Eclipse *Import...* menu. Cloning (hopefully batch) would be delegated to EGit. diff --git a/docs/03_faq.mkd b/docs/03_faq.mkd index fdc20200..3e99fb7a 100644 --- a/docs/03_faq.mkd +++ b/docs/03_faq.mkd @@ -61,6 +61,15 @@ You must ensure that the proxy does not decode and then re-encode request urls w If you are using Apache mod_proxy, specify [AllowEncodedSlashes NoDecode](http://httpd.apache.org/docs/2.2/mod/core.html#allowencodedslashes). +### Running Gitblit on Tomcat + +Tomcat takes the extra precaution of [disallowing embedded slashes by default](http://tomcat.apache.org/security-6.html#Fixed_in_Apache_Tomcat_6.0.10). This breaks Gitblit urls. +You have a few options on how to handle this scenario: + +1. [Tweak Tomcat](http://tomcat.apache.org/security-6.html#Fixed_in_Apache_Tomcat_6.0.10) +2. *web.mountParameters = false* and use non-pretty, parameterized urls +3. *web.forwardSlashCharacter = !* which tells Gitblit to use **!** instead of **/** + ## General Interest Questions ### Gitblit? What kind of name is that? diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java index 8386d2d4..19edf204 100644 --- a/src/com/gitblit/GitBlit.java +++ b/src/com/gitblit/GitBlit.java @@ -253,7 +253,7 @@ public class GitBlit implements ServletContextListener { * @return true if the update succeeded */ public boolean updateSettings(Map updatedSettings) { - return settings.saveSettings(updatedSettings); + return settings.saveSettings(updatedSettings); } public ServerStatus getStatus() { @@ -1389,7 +1389,7 @@ public class GitBlit implements ServletContextListener { repositoriesFolder = new File(settings.getString(Keys.git.repositoriesFolder, "git")); logger.info("Git repositories folder " + repositoriesFolder.getAbsolutePath()); repositoryResolver = new FileResolver(repositoriesFolder, exportAll); - serverStatus = new ServerStatus(); + serverStatus = new ServerStatus(isGO()); String realm = settings.getString(Keys.realm.userService, "users.properties"); IUserService loginService = null; try { @@ -1433,12 +1433,14 @@ public class GitBlit implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent contextEvent) { servletContext = contextEvent.getServletContext(); - settingsModel = loadSettingModels(); + settingsModel = loadSettingModels(); if (settings == null) { // Gitblit WAR is running in a servlet container WebXmlSettings webxmlSettings = new WebXmlSettings(contextEvent.getServletContext()); configureContext(webxmlSettings, true); } + + serverStatus.servletContainer = servletContext.getServerInfo(); } /** diff --git a/src/com/gitblit/RpcServlet.java b/src/com/gitblit/RpcServlet.java index 1136692a..dd99e3f4 100644 --- a/src/com/gitblit/RpcServlet.java +++ b/src/com/gitblit/RpcServlet.java @@ -199,7 +199,11 @@ public class RpcServlet extends JsonServlet { } } else if (RpcRequest.LIST_STATUS.equals(reqType)) { // return the server's status information - result = GitBlit.self().getStatus(); + if (GitBlit.getBoolean(Keys.web.enableRpcAdministration, false)) { + result = GitBlit.self().getStatus(); + } else { + response.sendError(notAllowedCode); + } } // send the result of the request diff --git a/src/com/gitblit/client/GitblitClient.java b/src/com/gitblit/client/GitblitClient.java index d3a92b0d..761283eb 100644 --- a/src/com/gitblit/client/GitblitClient.java +++ b/src/com/gitblit/client/GitblitClient.java @@ -87,7 +87,7 @@ public class GitblitClient implements Serializable { try { refreshSettings(); - status = RpcUtils.getStatus(url, account, password); + refreshStatus(); allowAdministration = true; } catch (UnauthorizedException e) { } catch (ForbiddenException e) { @@ -141,6 +141,11 @@ public class GitblitClient implements Serializable { settings = RpcUtils.getSettings(url, account, password); return settings; } + + public ServerStatus refreshStatus() throws IOException { + status = RpcUtils.getStatus(url, account, password); + return status; + } public List refreshFederationRegistrations() throws IOException { List list = RpcUtils.getFederationRegistrations(url, account, password); diff --git a/src/com/gitblit/client/GitblitPanel.java b/src/com/gitblit/client/GitblitPanel.java index d67921ba..1a24f71b 100644 --- a/src/com/gitblit/client/GitblitPanel.java +++ b/src/com/gitblit/client/GitblitPanel.java @@ -118,6 +118,8 @@ public class GitblitPanel extends JPanel implements CloseTabListener { private HeaderPanel settingsHeader; + private StatusPanel statusPanel; + public GitblitPanel(GitblitRegistration reg) { this(reg.url, reg.account, reg.password); } @@ -129,6 +131,7 @@ public class GitblitPanel extends JPanel implements CloseTabListener { tabs.addTab(Translation.get("gb.repositories"), createRepositoriesPanel()); tabs.addTab(Translation.get("gb.users"), createUsersPanel()); tabs.addTab(Translation.get("gb.settings"), createSettingsPanel()); + tabs.addTab(Translation.get("gb.status"), createStatusPanel()); setLayout(new BorderLayout()); add(tabs, BorderLayout.CENTER); @@ -482,6 +485,24 @@ public class GitblitPanel extends JPanel implements CloseTabListener { return settingsPanel; } + private JPanel createStatusPanel() { + JButton refreshStatus = new JButton(Translation.get("gb.refresh")); + refreshStatus.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + refreshStatus(); + } + }); + + JPanel controls = new JPanel(); + controls.add(refreshStatus); + + JPanel panel = new JPanel(new BorderLayout()); + statusPanel = new StatusPanel(); + panel.add(statusPanel, BorderLayout.CENTER); + panel.add(controls, BorderLayout.SOUTH); + return panel; + } + public void login() throws IOException { gitblit.login(); @@ -505,6 +526,7 @@ public class GitblitPanel extends JPanel implements CloseTabListener { if (gitblit.allowAdministration()) { updateSettingsTable(); + updateStatusPanel(); Utils.packColumns(settingsTable, 5); } else { // remove the settings tab @@ -539,6 +561,10 @@ public class GitblitPanel extends JPanel implements CloseTabListener { settingsHeader.setText(Translation.get("gb.settings")); } + private void updateStatusPanel() { + statusPanel.setStatus(gitblit.getStatus()); + } + private void filterRepositories(final String fragment) { if (StringUtils.isEmpty(fragment)) { repositoriesTable.setRowSorter(defaultRepositoriesSorter); @@ -934,6 +960,22 @@ public class GitblitPanel extends JPanel implements CloseTabListener { worker.execute(); } + protected void refreshStatus() { + GitblitWorker worker = new GitblitWorker(GitblitPanel.this, RpcRequest.LIST_STATUS) { + @Override + protected Boolean doRequest() throws IOException { + gitblit.refreshStatus(); + return true; + } + + @Override + protected void onSuccess() { + updateStatusPanel(); + } + }; + worker.execute(); + } + protected void editSetting(final SettingModel settingModel) { final JTextField textField = new JTextField(settingModel.currentValue); JPanel editPanel = new JPanel(new GridLayout(0, 1)); @@ -949,8 +991,8 @@ public class GitblitPanel extends JPanel implements CloseTabListener { if (settingModel.currentValue.equals(settingModel.defaultValue)) { options = new String[] { Translation.get("gb.cancel"), Translation.get("gb.save") }; } else { - options = new String[] { Translation.get("gb.cancel"), Translation.get("gb.setDefault"), - Translation.get("gb.save") }; + options = new String[] { Translation.get("gb.cancel"), + Translation.get("gb.setDefault"), Translation.get("gb.save") }; } String defaultOption = options[0]; int selection = JOptionPane.showOptionDialog(GitblitPanel.this, settingPanel, diff --git a/src/com/gitblit/client/PropertiesTableModel.java b/src/com/gitblit/client/PropertiesTableModel.java new file mode 100644 index 00000000..0c803f47 --- /dev/null +++ b/src/com/gitblit/client/PropertiesTableModel.java @@ -0,0 +1,106 @@ +/* + * Copyright 2011 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.client; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.table.AbstractTableModel; + +/** + * Table model of a map of properties. + * + * @author James Moger + * + */ +public class PropertiesTableModel extends AbstractTableModel { + + private static final long serialVersionUID = 1L; + + List keys; + + Map map; + + enum Columns { + Name, Value; + + @Override + public String toString() { + return name().replace('_', ' '); + } + } + + public PropertiesTableModel() { + this(new HashMap()); + } + + public PropertiesTableModel(Map map) { + setProperties(map); + } + + public void setProperties(Map map) { + this.map = map; + keys = new ArrayList(map.keySet()); + Collections.sort(this.keys); + } + + @Override + public int getRowCount() { + return keys.size(); + } + + @Override + public int getColumnCount() { + return Columns.values().length; + } + + @Override + public String getColumnName(int column) { + Columns col = Columns.values()[column]; + switch (col) { + case Name: + return Translation.get("gb.name"); + } + return ""; + } + + /** + * Returns Object.class regardless of columnIndex. + * + * @param columnIndex + * the column being queried + * @return the Object.class + */ + public Class getColumnClass(int columnIndex) { + return String.class; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + String key = keys.get(rowIndex); + Columns col = Columns.values()[columnIndex]; + switch (col) { + case Name: + return key; + case Value: + return map.get(key); + } + return null; + } +} diff --git a/src/com/gitblit/client/StatusPanel.java b/src/com/gitblit/client/StatusPanel.java new file mode 100644 index 00000000..9015c80f --- /dev/null +++ b/src/com/gitblit/client/StatusPanel.java @@ -0,0 +1,119 @@ +/* + * Copyright 2011 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.client; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.GridLayout; +import java.awt.Insets; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; + +import com.gitblit.models.ServerStatus; +import com.gitblit.utils.ByteFormat; + +/** + * This panel displays the server status. + * + * @author James Moger + */ +public class StatusPanel extends JPanel { + + private static final long serialVersionUID = 1L; + private final Insets insets = new Insets(5, 5, 5, 5); + private JLabel bootDate; + private JLabel servletContainer; + private JLabel heapMaximum; + private JLabel heapAllocated; + private JLabel heapUsed; + private PropertiesTableModel model; + private HeaderPanel headerPanel; + + public StatusPanel() { + super(); + initialize(); + } + + public StatusPanel(ServerStatus status) { + this(); + setStatus(status); + } + + private void initialize() { + bootDate = new JLabel(); + servletContainer = new JLabel(); + + heapMaximum = new JLabel(); + heapAllocated = new JLabel(); + heapUsed = new JLabel(); + + JPanel fieldsPanel = new JPanel(new GridLayout(0, 1)); + fieldsPanel.add(createFieldPanel("gb.bootDate", bootDate)); + fieldsPanel.add(createFieldPanel("gb.servletContainer", servletContainer)); + fieldsPanel.add(createFieldPanel("gb.heapUsed", heapUsed)); + fieldsPanel.add(createFieldPanel("gb.heapAllocated", heapAllocated)); + fieldsPanel.add(createFieldPanel("gb.heapMaximum", heapMaximum)); + + model = new PropertiesTableModel(); + JTable propertiesTable = Utils.newTable(model); + String name = propertiesTable.getColumnName(PropertiesTableModel.Columns.Name.ordinal()); + NameRenderer nameRenderer = new NameRenderer(); + propertiesTable.setRowHeight(nameRenderer.getFont().getSize() + 8); + propertiesTable.getColumn(name).setCellRenderer(nameRenderer); + + JPanel centerPanel = new JPanel(new BorderLayout()); + centerPanel.add(fieldsPanel, BorderLayout.NORTH); + centerPanel.add(new JScrollPane(propertiesTable), BorderLayout.CENTER); + + headerPanel = new HeaderPanel(Translation.get("gb.status"), null); + setLayout(new BorderLayout()); + add(headerPanel, BorderLayout.NORTH); + add(centerPanel, BorderLayout.CENTER); + } + + private JPanel createFieldPanel(String key, JLabel valueLabel) { + JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 5)); + JLabel textLabel = new JLabel(Translation.get(key)); + textLabel.setFont(textLabel.getFont().deriveFont(Font.BOLD)); + textLabel.setPreferredSize(new Dimension(120, valueLabel.getFont().getSize() + 4)); + panel.add(textLabel); + panel.add(valueLabel); + return panel; + } + + @Override + public Insets getInsets() { + return insets; + } + + public void setStatus(ServerStatus status) { + headerPanel.setText(Translation.get("gb.status")); + bootDate.setText(status.bootDate.toString()); + servletContainer.setText(status.servletContainer); + ByteFormat byteFormat = new ByteFormat(); + heapMaximum.setText(byteFormat.format(status.heapMaximum)); + heapAllocated.setText(byteFormat.format(status.heapAllocated)); + heapUsed.setText(byteFormat.format(status.heapAllocated - status.heapFree) + " (" + + byteFormat.format(status.heapFree) + " " + Translation.get("gb.free") + ")"); + model.setProperties(status.systemProperties); + model.fireTableDataChanged(); + } +} diff --git a/src/com/gitblit/models/ServerStatus.java b/src/com/gitblit/models/ServerStatus.java index 8dfc0fbc..1c40b5f4 100644 --- a/src/com/gitblit/models/ServerStatus.java +++ b/src/com/gitblit/models/ServerStatus.java @@ -33,18 +33,23 @@ public class ServerStatus implements Serializable { public final Date bootDate; + public final boolean isGO; + public final Map systemProperties; - public final long heapSize; + public final long heapMaximum; public volatile long heapAllocated; public volatile long heapFree; + + public String servletContainer; - public ServerStatus() { + public ServerStatus(boolean isGO) { bootDate = new Date(); + this.isGO = isGO; - heapSize = Runtime.getRuntime().maxMemory(); + heapMaximum = Runtime.getRuntime().maxMemory(); systemProperties = new TreeMap(); put("file.encoding"); diff --git a/src/com/gitblit/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties index 2052fb12..715cb156 100644 --- a/src/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/com/gitblit/wicket/GitBlitWebApp.properties @@ -166,4 +166,11 @@ gb.skipSummaryMetricsDescription = do not calculate metrics on the summary page gb.accessLevel = access level gb.default = default gb.setDefault = set default -gb.since = since \ No newline at end of file +gb.since = since +gb.status = status +gb.bootDate = boot date +gb.servletContainer = servlet container +gb.heapMaximum = maximum heap +gb.heapAllocated = allocated heap +gb.heapUsed = used heap +gb.free = free \ No newline at end of file
url parametersrequired
permission
json
url parametersrequired
user
permission
json
req=name=post bodyresponse body
web.enableRpcServlet=true
LIST_REPOSITORIES---Map<String, RepositoryModel>
web.enableRpcManagement=true
CREATE_REPOSITORYrepository nameadminRepositoryModel-
EDIT_REPOSITORYrepository nameadminRepositoryModel-
DELETE_REPOSITORYrepository nameadmin--
LIST_FEDERATION_RESULTS-admin-List<FederationModel>
LIST_FEDERATION_PROPOSALS-admin-List<FederationProposal>
LIST_FEDERATION_SETS-admin-List<FederationSet>
web.enableRpcAdministration=true
LIST_SETTINGS-admin-ServerSettings (see example below)
EDIT_SETTINGS-adminMap<String, String>-
LIST_STATUS-admin-ServerStatus (see example below)