mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-08 22:45:45 +01:00
Merged feature/changes_for_ssh_plugin into 2.0.0-m3
This commit is contained in:
@@ -77,15 +77,13 @@ public final class ScmState
|
|||||||
* @param repositoryTypes available repository types
|
* @param repositoryTypes available repository types
|
||||||
* @param defaultUserType default user type
|
* @param defaultUserType default user type
|
||||||
* @param clientConfig client configuration
|
* @param clientConfig client configuration
|
||||||
* @param assignedPermission assigned permissions
|
|
||||||
* @param availablePermissions list of available permissions
|
* @param availablePermissions list of available permissions
|
||||||
*
|
*
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
public ScmState(String version, User user, Collection<String> groups,
|
public ScmState(String version, User user, Collection<String> groups,
|
||||||
String token, Collection<RepositoryType> repositoryTypes, String defaultUserType,
|
String token, Collection<RepositoryType> repositoryTypes, String defaultUserType,
|
||||||
ScmClientConfig clientConfig, List<String> assignedPermission,
|
ScmClientConfig clientConfig, Collection<PermissionDescriptor> availablePermissions)
|
||||||
Collection<PermissionDescriptor> availablePermissions)
|
|
||||||
{
|
{
|
||||||
this.version = version;
|
this.version = version;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
@@ -94,24 +92,11 @@ public final class ScmState
|
|||||||
this.repositoryTypes = repositoryTypes;
|
this.repositoryTypes = repositoryTypes;
|
||||||
this.clientConfig = clientConfig;
|
this.clientConfig = clientConfig;
|
||||||
this.defaultUserType = defaultUserType;
|
this.defaultUserType = defaultUserType;
|
||||||
this.assignedPermissions = assignedPermission;
|
|
||||||
this.availablePermissions = availablePermissions;
|
this.availablePermissions = availablePermissions;
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
//~--- get methods ----------------------------------------------------------
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a list of assigned permissions.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return list of assigned permissions
|
|
||||||
* @since 1.31
|
|
||||||
*/
|
|
||||||
public List<String> getAssignedPermissions()
|
|
||||||
{
|
|
||||||
return assignedPermissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of available global permissions.
|
* Returns a list of available global permissions.
|
||||||
*
|
*
|
||||||
@@ -225,9 +210,6 @@ public final class ScmState
|
|||||||
/** authentication token */
|
/** authentication token */
|
||||||
private String token;
|
private String token;
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private List<String> assignedPermissions;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Avaliable global permission
|
* Avaliable global permission
|
||||||
* @since 1.31
|
* @since 1.31
|
||||||
|
|||||||
@@ -74,20 +74,17 @@ public final class ScmStateFactory
|
|||||||
* @param repositoryManger repository manager
|
* @param repositoryManger repository manager
|
||||||
* @param userManager user manager
|
* @param userManager user manager
|
||||||
* @param securitySystem security system
|
* @param securitySystem security system
|
||||||
* @param authorizationCollector authorization collector
|
|
||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
public ScmStateFactory(SCMContextProvider contextProvider,
|
public ScmStateFactory(SCMContextProvider contextProvider,
|
||||||
ScmConfiguration configuration, RepositoryManager repositoryManger,
|
ScmConfiguration configuration, RepositoryManager repositoryManger,
|
||||||
UserManager userManager, SecuritySystem securitySystem,
|
UserManager userManager, SecuritySystem securitySystem)
|
||||||
AuthorizationCollector authorizationCollector)
|
|
||||||
{
|
{
|
||||||
this.contextProvider = contextProvider;
|
this.contextProvider = contextProvider;
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
this.repositoryManger = repositoryManger;
|
this.repositoryManger = repositoryManger;
|
||||||
this.userManager = userManager;
|
this.userManager = userManager;
|
||||||
this.securitySystem = securitySystem;
|
this.securitySystem = securitySystem;
|
||||||
this.authorizationCollector = authorizationCollector;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
//~--- methods --------------------------------------------------------------
|
||||||
@@ -101,8 +98,7 @@ public final class ScmStateFactory
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public ScmState createAnonymousState()
|
public ScmState createAnonymousState()
|
||||||
{
|
{
|
||||||
return createState(SCMContext.ANONYMOUS, Collections.EMPTY_LIST, null,
|
return createState(SCMContext.ANONYMOUS, Collections.EMPTY_LIST, null, Collections.EMPTY_LIST);
|
||||||
Collections.EMPTY_LIST, Collections.EMPTY_LIST);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -141,15 +137,11 @@ public final class ScmStateFactory
|
|||||||
ap = securitySystem.getAvailablePermissions();
|
ap = securitySystem.getAvailablePermissions();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> permissions =
|
return createState(user, groups.getCollection(), token, ap);
|
||||||
ImmutableList.copyOf(
|
|
||||||
authorizationCollector.collect().getStringPermissions());
|
|
||||||
|
|
||||||
return createState(user, groups.getCollection(), token, permissions, ap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScmState createState(User user, Collection<String> groups,
|
private ScmState createState(User user, Collection<String> groups,
|
||||||
String token, List<String> assignedPermissions,
|
String token,
|
||||||
Collection<PermissionDescriptor> availablePermissions)
|
Collection<PermissionDescriptor> availablePermissions)
|
||||||
{
|
{
|
||||||
User u = user.clone();
|
User u = user.clone();
|
||||||
@@ -159,15 +151,11 @@ public final class ScmStateFactory
|
|||||||
|
|
||||||
return new ScmState(contextProvider.getVersion(), u, groups, token,
|
return new ScmState(contextProvider.getVersion(), u, groups, token,
|
||||||
repositoryManger.getConfiguredTypes(), userManager.getDefaultType(),
|
repositoryManger.getConfiguredTypes(), userManager.getDefaultType(),
|
||||||
new ScmClientConfig(configuration), assignedPermissions,
|
new ScmClientConfig(configuration), availablePermissions);
|
||||||
availablePermissions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|
||||||
/** authorization collector */
|
|
||||||
private final AuthorizationCollector authorizationCollector;
|
|
||||||
|
|
||||||
/** configuration */
|
/** configuration */
|
||||||
private final ScmConfiguration configuration;
|
private final ScmConfiguration configuration;
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,29 @@ package sonia.scm.repository.api;
|
|||||||
import sonia.scm.plugin.ExtensionPoint;
|
import sonia.scm.plugin.ExtensionPoint;
|
||||||
import sonia.scm.repository.Repository;
|
import sonia.scm.repository.Repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for scm native protocols.
|
||||||
|
*
|
||||||
|
* @param <T> type of protocol
|
||||||
|
*
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
@ExtensionPoint(multi = true)
|
@ExtensionPoint(multi = true)
|
||||||
public interface ScmProtocolProvider<T extends ScmProtocol> {
|
public interface ScmProtocolProvider<T extends ScmProtocol> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns type of repository (e.g.: git, svn, hg, etc.)
|
||||||
|
*
|
||||||
|
* @return name of type
|
||||||
|
*/
|
||||||
String getType();
|
String getType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns protocol for the given repository.
|
||||||
|
*
|
||||||
|
* @param repository repository
|
||||||
|
*
|
||||||
|
* @return protocol for repository
|
||||||
|
*/
|
||||||
T get(Repository repository);
|
T get(Repository repository);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ package sonia.scm.security;
|
|||||||
//~--- non-JDK imports --------------------------------------------------------
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
import org.apache.shiro.authz.AuthorizationInfo;
|
import org.apache.shiro.authz.AuthorizationInfo;
|
||||||
|
import org.apache.shiro.subject.PrincipalCollection;
|
||||||
import sonia.scm.plugin.ExtensionPoint;
|
import sonia.scm.plugin.ExtensionPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,15 +43,16 @@ import sonia.scm.plugin.ExtensionPoint;
|
|||||||
* @author Sebastian Sdorra
|
* @author Sebastian Sdorra
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
@ExtensionPoint(multi = false)
|
@ExtensionPoint
|
||||||
public interface AuthorizationCollector
|
public interface AuthorizationCollector
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@link AuthorizationInfo} for the authenticated user.
|
* Returns {@link AuthorizationInfo} for the authenticated user.
|
||||||
*
|
*
|
||||||
|
* @param principalCollection collected principals
|
||||||
*
|
*
|
||||||
* @return {@link AuthorizationInfo} for authenticated user
|
* @return {@link AuthorizationInfo} for authenticated user
|
||||||
*/
|
*/
|
||||||
public AuthorizationInfo collect();
|
AuthorizationInfo collect(PrincipalCollection principalCollection);
|
||||||
}
|
}
|
||||||
|
|||||||
57
scm-plugins/scm-git-plugin/src/main/js/CloneInformation.js
Normal file
57
scm-plugins/scm-git-plugin/src/main/js/CloneInformation.js
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import { translate } from "react-i18next";
|
||||||
|
import type { Repository } from "@scm-manager/ui-types";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
url: string,
|
||||||
|
repository: Repository,
|
||||||
|
|
||||||
|
// context props
|
||||||
|
t: (string) => string
|
||||||
|
};
|
||||||
|
|
||||||
|
class CloneInformation extends React.Component<Props> {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { url, repository, t } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h4>{t("scm-git-plugin.information.clone")}</h4>
|
||||||
|
<pre>
|
||||||
|
<code>git clone {url}</code>
|
||||||
|
</pre>
|
||||||
|
<h4>{t("scm-git-plugin.information.create")}</h4>
|
||||||
|
<pre>
|
||||||
|
<code>
|
||||||
|
git init {repository.name}
|
||||||
|
<br />
|
||||||
|
echo "# {repository.name}" > README.md
|
||||||
|
<br />
|
||||||
|
git add README.md
|
||||||
|
<br />
|
||||||
|
git commit -m "added readme"
|
||||||
|
<br />
|
||||||
|
git remote add origin {url}
|
||||||
|
<br />
|
||||||
|
git push -u origin master
|
||||||
|
<br />
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
<h4>{t("scm-git-plugin.information.replace")}</h4>
|
||||||
|
<pre>
|
||||||
|
<code>
|
||||||
|
git remote add origin {url}
|
||||||
|
<br />
|
||||||
|
git push -u origin master
|
||||||
|
<br />
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default translate("plugins")(CloneInformation);
|
||||||
@@ -1,59 +1,108 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { repositories } from "@scm-manager/ui-components";
|
import { ButtonGroup, Button } from "@scm-manager/ui-components";
|
||||||
import type { Repository } from "@scm-manager/ui-types";
|
import type { Repository } from "@scm-manager/ui-types";
|
||||||
import { translate } from "react-i18next";
|
import CloneInformation from "./CloneInformation";
|
||||||
|
import type { Link } from "@scm-manager/ui-types";
|
||||||
|
import injectSheets from "react-jss";
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
protocols: {
|
||||||
|
position: "relative"
|
||||||
|
},
|
||||||
|
switcher: {
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
right: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
repository: Repository,
|
repository: Repository,
|
||||||
t: string => string
|
|
||||||
|
// context props
|
||||||
|
classes: Object
|
||||||
}
|
}
|
||||||
|
|
||||||
class ProtocolInformation extends React.Component<Props> {
|
type State = {
|
||||||
|
selected?: Link
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
function selectHttpOrFirst(repository: Repository) {
|
||||||
const { repository, t } = this.props;
|
const protocols = repository._links["protocol"] || [];
|
||||||
const href = repositories.getProtocolLinkByType(repository, "http");
|
|
||||||
if (!href) {
|
for (let protocol of protocols) {
|
||||||
return null;
|
if (protocol.name === "http") {
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (protocols.length > 0) {
|
||||||
|
return protocols[0];
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProtocolInformation extends React.Component<Props, State> {
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
selected: selectHttpOrFirst(props.repository)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
selectProtocol = (protocol: Link) => {
|
||||||
|
this.setState({
|
||||||
|
selected: protocol
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
renderProtocolButton = (protocol: Link) => {
|
||||||
|
const name = protocol.name || "unknown";
|
||||||
|
|
||||||
|
let color = null;
|
||||||
|
|
||||||
|
const { selected } = this.state;
|
||||||
|
if ( selected && protocol.name === selected.name ) {
|
||||||
|
color = "link is-selected";
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<Button color={ color } action={() => this.selectProtocol(protocol)}>
|
||||||
<h4>{t("scm-git-plugin.information.clone")}</h4>
|
{name.toUpperCase()}
|
||||||
<pre>
|
</Button>
|
||||||
<code>git clone {href}</code>
|
);
|
||||||
</pre>
|
};
|
||||||
<h4>{t("scm-git-plugin.information.create")}</h4>
|
|
||||||
<pre>
|
render() {
|
||||||
<code>
|
const { repository, classes } = this.props;
|
||||||
git init {repository.name}
|
|
||||||
<br />
|
const protocols = repository._links["protocol"];
|
||||||
echo "# {repository.name}" > README.md
|
if (!protocols || protocols.length === 0) {
|
||||||
<br />
|
return null;
|
||||||
git add README.md
|
}
|
||||||
<br />
|
|
||||||
git commit -m "added readme"
|
if (protocols.length === 1) {
|
||||||
<br />
|
return <CloneInformation url={protocols[0].href} repository={repository} />;
|
||||||
git remote add origin {href}
|
}
|
||||||
<br />
|
|
||||||
git push -u origin master
|
const { selected } = this.state;
|
||||||
<br />
|
let cloneInformation = null;
|
||||||
</code>
|
if (selected) {
|
||||||
</pre>
|
cloneInformation = <CloneInformation repository={repository} url={selected.href} />;
|
||||||
<h4>{t("scm-git-plugin.information.replace")}</h4>
|
}
|
||||||
<pre>
|
|
||||||
<code>
|
return (
|
||||||
git remote add origin {href}
|
<div className={classes.protocols}>
|
||||||
<br />
|
<ButtonGroup className={classes.switcher}>
|
||||||
git push -u origin master
|
{protocols.map(this.renderProtocolButton)}
|
||||||
<br />
|
</ButtonGroup>
|
||||||
</code>
|
{ cloneInformation }
|
||||||
</pre>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translate("plugins")(ProtocolInformation);
|
export default injectSheets(styles)(ProtocolInformation);
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ class Profile extends React.Component<Props, State> {
|
|||||||
path={`${url}/settings/password`}
|
path={`${url}/settings/password`}
|
||||||
render={() => <ChangeUserPassword me={me} />}
|
render={() => <ChangeUserPassword me={me} />}
|
||||||
/>
|
/>
|
||||||
|
<ExtensionPoint
|
||||||
|
name="profile.route"
|
||||||
|
props={extensionProps}
|
||||||
|
renderAll={true}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="column">
|
<div className="column">
|
||||||
<Navigation>
|
<Navigation>
|
||||||
|
|||||||
@@ -105,6 +105,11 @@ class SingleUser extends React.Component<Props> {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<ExtensionPoint
|
||||||
|
name="user.route"
|
||||||
|
props={extensionProps}
|
||||||
|
renderAll={true}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="column">
|
<div className="column">
|
||||||
<Navigation>
|
<Navigation>
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ package sonia.scm.security;
|
|||||||
//~--- non-JDK imports --------------------------------------------------------
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
import com.github.legman.Subscribe;
|
import com.github.legman.Subscribe;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
@@ -118,8 +119,8 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
@VisibleForTesting
|
||||||
public AuthorizationInfo collect()
|
AuthorizationInfo collect()
|
||||||
{
|
{
|
||||||
AuthorizationInfo authorizationInfo;
|
AuthorizationInfo authorizationInfo;
|
||||||
Subject subject = SecurityUtils.getSubject();
|
Subject subject = SecurityUtils.getSubject();
|
||||||
@@ -143,6 +144,7 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public AuthorizationInfo collect(PrincipalCollection principals)
|
public AuthorizationInfo collect(PrincipalCollection principals)
|
||||||
{
|
{
|
||||||
Preconditions.checkNotNull(principals, "principals parameter is required");
|
Preconditions.checkNotNull(principals, "principals parameter is required");
|
||||||
|
|||||||
@@ -42,9 +42,11 @@ import org.apache.shiro.authc.UsernamePasswordToken;
|
|||||||
import org.apache.shiro.authc.credential.PasswordMatcher;
|
import org.apache.shiro.authc.credential.PasswordMatcher;
|
||||||
import org.apache.shiro.authc.credential.PasswordService;
|
import org.apache.shiro.authc.credential.PasswordService;
|
||||||
import org.apache.shiro.authz.AuthorizationInfo;
|
import org.apache.shiro.authz.AuthorizationInfo;
|
||||||
|
import org.apache.shiro.authz.SimpleAuthorizationInfo;
|
||||||
import org.apache.shiro.realm.AuthorizingRealm;
|
import org.apache.shiro.realm.AuthorizingRealm;
|
||||||
import org.apache.shiro.subject.PrincipalCollection;
|
import org.apache.shiro.subject.PrincipalCollection;
|
||||||
|
|
||||||
|
import org.apache.shiro.subject.SimplePrincipalCollection;
|
||||||
import sonia.scm.group.GroupNames;
|
import sonia.scm.group.GroupNames;
|
||||||
import sonia.scm.plugin.Extension;
|
import sonia.scm.plugin.Extension;
|
||||||
|
|
||||||
@@ -56,6 +58,8 @@ import javax.inject.Singleton;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default authorizing realm.
|
* Default authorizing realm.
|
||||||
*
|
*
|
||||||
@@ -85,14 +89,13 @@ public class DefaultRealm extends AuthorizingRealm
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param service
|
* @param service
|
||||||
* @param collector
|
* @param authorizationCollectors
|
||||||
* @param helperFactory
|
* @param helperFactory
|
||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
public DefaultRealm(PasswordService service,
|
public DefaultRealm(PasswordService service, Set<AuthorizationCollector> authorizationCollectors, DAORealmHelperFactory helperFactory)
|
||||||
DefaultAuthorizationCollector collector, DAORealmHelperFactory helperFactory)
|
|
||||||
{
|
{
|
||||||
this.collector = collector;
|
this.authorizationCollectors = authorizationCollectors;
|
||||||
this.helper = helperFactory.create(REALM);
|
this.helper = helperFactory.create(REALM);
|
||||||
|
|
||||||
PasswordMatcher matcher = new PasswordMatcher();
|
PasswordMatcher matcher = new PasswordMatcher();
|
||||||
@@ -133,8 +136,7 @@ public class DefaultRealm extends AuthorizingRealm
|
|||||||
@Override
|
@Override
|
||||||
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals)
|
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals)
|
||||||
{
|
{
|
||||||
AuthorizationInfo info = collector.collect(principals);
|
AuthorizationInfo info = collectors(principals);
|
||||||
|
|
||||||
Scope scope = principals.oneByType(Scope.class);
|
Scope scope = principals.oneByType(Scope.class);
|
||||||
if (scope != null && ! scope.isEmpty()) {
|
if (scope != null && ! scope.isEmpty()) {
|
||||||
LOG.trace("filter permissions by scope {}", scope);
|
LOG.trace("filter permissions by scope {}", scope);
|
||||||
@@ -144,13 +146,36 @@ public class DefaultRealm extends AuthorizingRealm
|
|||||||
}
|
}
|
||||||
return filtered;
|
return filtered;
|
||||||
} else if (LOG.isTraceEnabled()) {
|
} else if (LOG.isTraceEnabled()) {
|
||||||
LOG.trace("principal does not contain scope informations, returning all permissions");
|
LOG.trace("principal does not contain scope information, returning all permissions");
|
||||||
log(principals, info, null);
|
log(principals, info, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AuthorizationInfo collectors(PrincipalCollection principals) {
|
||||||
|
SimpleAuthorizationInfo merged = new SimpleAuthorizationInfo();
|
||||||
|
for (AuthorizationCollector collector : authorizationCollectors) {
|
||||||
|
AuthorizationInfo authorizationInfo = collector.collect(principals);
|
||||||
|
merge(merged, authorizationInfo);
|
||||||
|
}
|
||||||
|
return merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void merge(SimpleAuthorizationInfo merged, AuthorizationInfo authorizationInfo) {
|
||||||
|
if (authorizationInfo != null) {
|
||||||
|
if (authorizationInfo.getRoles() != null) {
|
||||||
|
merged.addRoles(authorizationInfo.getRoles());
|
||||||
|
}
|
||||||
|
if (authorizationInfo.getObjectPermissions() != null) {
|
||||||
|
merged.addObjectPermissions(authorizationInfo.getObjectPermissions());
|
||||||
|
}
|
||||||
|
if (authorizationInfo.getStringPermissions() != null) {
|
||||||
|
merged.addStringPermissions(authorizationInfo.getStringPermissions());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void log( PrincipalCollection collection, AuthorizationInfo original, AuthorizationInfo filtered ) {
|
private void log( PrincipalCollection collection, AuthorizationInfo original, AuthorizationInfo filtered ) {
|
||||||
StringBuilder buffer = new StringBuilder("authorization summary: ");
|
StringBuilder buffer = new StringBuilder("authorization summary: ");
|
||||||
|
|
||||||
@@ -190,8 +215,8 @@ public class DefaultRealm extends AuthorizingRealm
|
|||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|
||||||
/** default authorization collector */
|
/** set of authorization collector */
|
||||||
private final DefaultAuthorizationCollector collector;
|
private final Set<AuthorizationCollector> authorizationCollectors;
|
||||||
|
|
||||||
/** realm helper */
|
/** realm helper */
|
||||||
private final DAORealmHelper helper;
|
private final DAORealmHelper helper;
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ private long calculateAverage(List<Long> times) {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
|
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
|
||||||
return authzCollector.collect();
|
return authzCollector.collect(principals);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,11 @@ import static org.mockito.Mockito.*;
|
|||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.shiro.authz.AuthorizationInfo;
|
import org.apache.shiro.authz.AuthorizationInfo;
|
||||||
import org.apache.shiro.authz.Permission;
|
import org.apache.shiro.authz.Permission;
|
||||||
import org.apache.shiro.authz.SimpleAuthorizationInfo;
|
import org.apache.shiro.authz.SimpleAuthorizationInfo;
|
||||||
@@ -132,6 +136,36 @@ public class DefaultRealmTest
|
|||||||
assertThat(realmsAutz.getStringPermissions(), Matchers.contains("repository:*"));
|
assertThat(realmsAutz.getStringPermissions(), Matchers.contains("repository:*"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAuthorizationInfoWithMultipleAuthorizationCollectors(){
|
||||||
|
SimplePrincipalCollection col = new SimplePrincipalCollection();
|
||||||
|
col.add(Scope.empty(), DefaultRealm.REALM);
|
||||||
|
|
||||||
|
SimpleAuthorizationInfo collectedFromDefault = new SimpleAuthorizationInfo();
|
||||||
|
collectedFromDefault.addStringPermission("repository:*");
|
||||||
|
when(collector.collect(col)).thenReturn(collectedFromDefault);
|
||||||
|
|
||||||
|
SimpleAuthorizationInfo collectedFromSecond = new SimpleAuthorizationInfo();
|
||||||
|
collectedFromSecond.addStringPermission("user:*");
|
||||||
|
collectedFromSecond.addRole("awesome");
|
||||||
|
|
||||||
|
AuthorizationCollector secondCollector = principalCollection -> collectedFromSecond;
|
||||||
|
authorizationCollectors.add(secondCollector);
|
||||||
|
|
||||||
|
SimpleAuthorizationInfo collectedFromThird = new SimpleAuthorizationInfo();
|
||||||
|
Permission permission = p -> false;
|
||||||
|
collectedFromThird.addObjectPermission(permission);
|
||||||
|
collectedFromThird.addRole("awesome");
|
||||||
|
|
||||||
|
AuthorizationCollector thirdCollector = principalCollection -> collectedFromThird;
|
||||||
|
authorizationCollectors.add(thirdCollector);
|
||||||
|
|
||||||
|
AuthorizationInfo realmsAuthz = realm.doGetAuthorizationInfo(col);
|
||||||
|
assertThat(realmsAuthz.getObjectPermissions(), contains(permission));
|
||||||
|
assertThat(realmsAuthz.getStringPermissions(), containsInAnyOrder("repository:*", "user:*"));
|
||||||
|
assertThat(realmsAuthz.getRoles(), Matchers.contains("awesome"));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link DefaultRealm#doGetAuthorizationInfo(PrincipalCollection)} with empty scope.
|
* Tests {@link DefaultRealm#doGetAuthorizationInfo(PrincipalCollection)} with empty scope.
|
||||||
*/
|
*/
|
||||||
@@ -284,7 +318,11 @@ public class DefaultRealmTest
|
|||||||
// use a small number of iterations for faster test execution
|
// use a small number of iterations for faster test execution
|
||||||
hashService.setHashIterations(512);
|
hashService.setHashIterations(512);
|
||||||
service.setHashService(hashService);
|
service.setHashService(hashService);
|
||||||
realm = new DefaultRealm(service, collector, helperFactory);
|
|
||||||
|
authorizationCollectors = new HashSet<>();
|
||||||
|
authorizationCollectors.add(collector);
|
||||||
|
|
||||||
|
realm = new DefaultRealm(service, authorizationCollectors, helperFactory);
|
||||||
|
|
||||||
// set permission resolver
|
// set permission resolver
|
||||||
realm.setPermissionResolver(new WildcardPermissionResolver());
|
realm.setPermissionResolver(new WildcardPermissionResolver());
|
||||||
@@ -358,6 +396,8 @@ public class DefaultRealmTest
|
|||||||
@Mock
|
@Mock
|
||||||
private DefaultAuthorizationCollector collector;
|
private DefaultAuthorizationCollector collector;
|
||||||
|
|
||||||
|
private Set<AuthorizationCollector> authorizationCollectors;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private LoginAttemptHandler loginAttemptHandler;
|
private LoginAttemptHandler loginAttemptHandler;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user