removes admin flag from user object

This commit is contained in:
Sebastian Sdorra
2019-03-13 12:07:18 +01:00
parent 9d0e3e568a
commit a2f83e2429
12 changed files with 193 additions and 267 deletions

View File

@@ -157,12 +157,6 @@ public class User extends BasicPropertiesAware implements Principal, ModelObject
{
boolean result = false;
if (user.isAdmin() != admin)
{
result = true;
user.setAdmin(admin);
}
if (user.isActive() != active)
{
result = true;
@@ -229,7 +223,6 @@ public class User extends BasicPropertiesAware implements Principal, ModelObject
&& Objects.equal(displayName, other.displayName)
&& Objects.equal(mail, other.mail)
&& Objects.equal(type, other.type)
&& Objects.equal(admin, other.admin)
&& Objects.equal(active, other.active)
&& Objects.equal(password, other.password)
&& Objects.equal(creationDate, other.creationDate)
@@ -246,7 +239,7 @@ public class User extends BasicPropertiesAware implements Principal, ModelObject
@Override
public int hashCode()
{
return Objects.hashCode(name, displayName, mail, type, admin, password,
return Objects.hashCode(name, displayName, mail, type, password,
active, creationDate, lastModified, properties);
}
@@ -269,7 +262,6 @@ public class User extends BasicPropertiesAware implements Principal, ModelObject
.add("displayName",displayName)
.add("mail", mail)
.add("password", pwd)
.add("admin", admin)
.add("type", type)
.add("active", active)
.add("creationDate", creationDate)
@@ -385,17 +377,6 @@ public class User extends BasicPropertiesAware implements Principal, ModelObject
return active;
}
/**
* Method description
*
*
* @return
*/
public boolean isAdmin()
{
return admin;
}
/**
* Method description
*
@@ -424,17 +405,6 @@ public class User extends BasicPropertiesAware implements Principal, ModelObject
this.active = active;
}
/**
* Method description
*
*
* @param admin
*/
public void setAdmin(boolean admin)
{
this.admin = admin;
}
/**
* Method description
*
@@ -518,9 +488,6 @@ public class User extends BasicPropertiesAware implements Principal, ModelObject
/** Field description */
private boolean active = true;
/** Field description */
private boolean admin = false;
/** Field description */
private Long creationDate;

View File

@@ -6,7 +6,6 @@ export type User = {
name: string,
mail: string,
password: string,
admin: boolean,
active: boolean,
type?: string,
creationDate?: string,

View File

@@ -37,7 +37,6 @@ class UserForm extends React.Component<Props, State> {
displayName: "",
mail: "",
password: "",
admin: false,
active: true,
_links: {}
},
@@ -167,12 +166,6 @@ class UserForm extends React.Component<Props, State> {
<div className="columns">
<div className="column">
{passwordChangeField}
<Checkbox
label={t("user.admin")}
onChange={this.handleAdminChange}
checked={user ? user.admin : false}
helpText={t("help.adminHelpText")}
/>
<Checkbox
label={t("user.active")}
onChange={this.handleActiveChange}
@@ -225,10 +218,6 @@ class UserForm extends React.Component<Props, State> {
});
};
handleAdminChange = (admin: boolean) => {
this.setState({ user: { ...this.state.user, admin } });
};
handleActiveChange = (active: boolean) => {
this.setState({ user: { ...this.state.user, active } });
};

View File

@@ -1,66 +1,60 @@
//@flow
import React from "react";
import type { User } from "@scm-manager/ui-types";
import { translate } from "react-i18next";
import { Checkbox, MailLink, DateFromNow } from "@scm-manager/ui-components";
type Props = {
user: User,
t: string => string
};
class Details extends React.Component<Props> {
render() {
const { user, t } = this.props;
return (
<table className="table">
<tbody>
<tr>
<td className="has-text-weight-semibold">{t("user.name")}</td>
<td>{user.name}</td>
</tr>
<tr>
<td className="has-text-weight-semibold">{t("user.displayName")}</td>
<td>{user.displayName}</td>
</tr>
<tr>
<td className="has-text-weight-semibold">{t("user.mail")}</td>
<td>
<MailLink address={user.mail} />
</td>
</tr>
<tr>
<td className="has-text-weight-semibold">{t("user.admin")}</td>
<td>
<Checkbox checked={user.admin} />
</td>
</tr>
<tr>
<td className="has-text-weight-semibold">{t("user.active")}</td>
<td>
<Checkbox checked={user.active} />
</td>
</tr>
<tr>
<td className="has-text-weight-semibold">{t("user.type")}</td>
<td>{user.type}</td>
</tr>
<tr>
<td className="has-text-weight-semibold">{t("user.creationDate")}</td>
<td>
<DateFromNow date={user.creationDate} />
</td>
</tr>
<tr>
<td className="has-text-weight-semibold">{t("user.lastModified")}</td>
<td>
<DateFromNow date={user.lastModified} />
</td>
</tr>
</tbody>
</table>
);
}
}
export default translate("users")(Details);
//@flow
import React from "react";
import type { User } from "@scm-manager/ui-types";
import { translate } from "react-i18next";
import { Checkbox, MailLink, DateFromNow } from "@scm-manager/ui-components";
type Props = {
user: User,
t: string => string
};
class Details extends React.Component<Props> {
render() {
const { user, t } = this.props;
return (
<table className="table">
<tbody>
<tr>
<td className="has-text-weight-semibold">{t("user.name")}</td>
<td>{user.name}</td>
</tr>
<tr>
<td className="has-text-weight-semibold">{t("user.displayName")}</td>
<td>{user.displayName}</td>
</tr>
<tr>
<td className="has-text-weight-semibold">{t("user.mail")}</td>
<td>
<MailLink address={user.mail} />
</td>
</tr>
<tr>
<td className="has-text-weight-semibold">{t("user.active")}</td>
<td>
<Checkbox checked={user.active} />
</td>
</tr>
<tr>
<td className="has-text-weight-semibold">{t("user.type")}</td>
<td>{user.type}</td>
</tr>
<tr>
<td className="has-text-weight-semibold">{t("user.creationDate")}</td>
<td>
<DateFromNow date={user.creationDate} />
</td>
</tr>
<tr>
<td className="has-text-weight-semibold">{t("user.lastModified")}</td>
<td>
<DateFromNow date={user.lastModified} />
</td>
</tr>
</tbody>
</table>
);
}
}
export default translate("users")(Details);

View File

@@ -1,31 +1,31 @@
// @flow
import React from "react";
import { Link } from "react-router-dom";
import type { User } from "@scm-manager/ui-types";
type Props = {
user: User
};
export default class UserRow extends React.Component<Props> {
renderLink(to: string, label: string) {
return <Link to={to}>{label}</Link>;
}
render() {
const { user } = this.props;
const to = `/user/${user.name}`;
return (
<tr>
<td className="is-hidden-mobile">{this.renderLink(to, user.name)}</td>
<td>{this.renderLink(to, user.displayName)}</td>
<td>
<a href={`mailto: ${user.mail}`}>{user.mail}</a>
</td>
<td className="is-hidden-mobile">
<input type="checkbox" id="admin" checked={user.admin} readOnly />
</td>
</tr>
);
}
}
// @flow
import React from "react";
import { Link } from "react-router-dom";
import type { User } from "@scm-manager/ui-types";
type Props = {
user: User
};
export default class UserRow extends React.Component<Props> {
renderLink(to: string, label: string) {
return <Link to={to}>{label}</Link>;
}
render() {
const { user } = this.props;
const to = `/user/${user.name}`;
return (
<tr>
<td className="is-hidden-mobile">{this.renderLink(to, user.name)}</td>
<td>{this.renderLink(to, user.displayName)}</td>
<td>
<a href={`mailto: ${user.mail}`}>{user.mail}</a>
</td>
<td className="is-hidden-mobile">
<input type="checkbox" id="active" checked={user.active} readOnly />
</td>
</tr>
);
}
}

View File

@@ -1,37 +1,37 @@
// @flow
import React from "react";
import { translate } from "react-i18next";
import UserRow from "./UserRow";
import type { User } from "@scm-manager/ui-types";
type Props = {
t: string => string,
users: User[]
};
;
class UserTable extends React.Component<Props> {
render() {
const { users, t } = this.props;
return (
<table className="card-table table is-hoverable is-fullwidth">
<thead>
<tr>
<th className="is-hidden-mobile">{t("user.name")}</th>
<th>{t("user.displayName")}</th>
<th>{t("user.mail")}</th>
<th className="is-hidden-mobile">{t("user.admin")}</th>
</tr>
</thead>
<tbody>
{users.map((user, index) => {
return <UserRow key={index} user={user} />;
})}
</tbody>
</table>
);
}
}
export default translate("users")(UserTable);
// @flow
import React from "react";
import { translate } from "react-i18next";
import UserRow from "./UserRow";
import type { User } from "@scm-manager/ui-types";
type Props = {
t: string => string,
users: User[]
};
;
class UserTable extends React.Component<Props> {
render() {
const { users, t } = this.props;
return (
<table className="card-table table is-hoverable is-fullwidth">
<thead>
<tr>
<th className="is-hidden-mobile">{t("user.name")}</th>
<th>{t("user.displayName")}</th>
<th>{t("user.mail")}</th>
<th className="is-hidden-mobile">{t("user.active")}</th>
</tr>
</thead>
<tbody>
{users.map((user, index) => {
return <UserRow key={index} user={user} />;
})}
</tbody>
</table>
);
}
}
export default translate("users")(UserTable);

View File

@@ -49,15 +49,15 @@ import sonia.scm.user.UserEvent;
import sonia.scm.user.UserModificationEvent;
/**
* Receives all kinds of events, which affects authorization relevant data and fires an
* Receives all kinds of events, which affects authorization relevant data and fires an
* {@link AuthorizationChangedEvent} if authorization data has changed.
*
*
* @author Sebastian Sdorra
* @since 1.52
*/
@EagerSingleton
public class AuthorizationChangedEventProducer {
/**
* the logger for AuthorizationChangedEventProducer
*/
@@ -68,7 +68,7 @@ public class AuthorizationChangedEventProducer {
*/
public AuthorizationChangedEventProducer() {
}
/**
* Invalidates the cache of a user which was modified. The cache entries for the user will be invalidated for the
* following reasons:
@@ -90,11 +90,11 @@ public class AuthorizationChangedEventProducer {
}
}
}
private boolean isModificationEvent(HandlerEvent<?> event) {
return event instanceof ModificationHandlerEvent;
}
private void handleUserEvent(UserEvent event) {
String username = event.getItem().getName();
logger.debug(
@@ -102,26 +102,26 @@ public class AuthorizationChangedEventProducer {
);
fireEventForUser(username);
}
private void handleUserModificationEvent(UserModificationEvent event) {
String username = event.getItem().getId();
User beforeModification = event.getItemBeforeModification();
if (isAuthorizationDataModified(event.getItem(), beforeModification)) {
logger.debug(
"fire authorization changed event for user {}, because of a authorization relevant field has changed",
"fire authorization changed event for user {}, because of a authorization relevant field has changed",
username
);
fireEventForUser(username);
} else {
logger.debug(
"authorization changed event for user {} is not fired, because no authorization relevant field has changed",
"authorization changed event for user {} is not fired, because no authorization relevant field has changed",
username
);
}
}
private boolean isAuthorizationDataModified(User user, User beforeModification) {
return user.isAdmin() != beforeModification.isAdmin() || user.isActive() != beforeModification.isActive();
return user.isActive() != beforeModification.isActive();
}
private void fireEventForUser(String username) {
@@ -148,7 +148,7 @@ public class AuthorizationChangedEventProducer {
}
}
}
private void handleRepositoryModificationEvent(RepositoryModificationEvent event) {
Repository repository = event.getItem();
if (isAuthorizationDataModified(repository, event.getItemBeforeModification())) {
@@ -169,14 +169,14 @@ public class AuthorizationChangedEventProducer {
|| repository.isPublicReadable() != beforeModification.isPublicReadable()
|| !(repository.getPermissions().containsAll(beforeModification.getPermissions()) && beforeModification.getPermissions().containsAll(repository.getPermissions()));
}
private void fireEventForEveryUser() {
sendEvent(AuthorizationChangedEvent.createForEveryUser());
}
private void handleRepositoryEvent(RepositoryEvent event){
logger.debug(
"fire authorization changed event, because of received {} event for repository {}",
"fire authorization changed event, because of received {} event for repository {}",
event.getEventType(), event.getItem().getName()
);
fireEventForEveryUser();
@@ -199,7 +199,7 @@ public class AuthorizationChangedEventProducer {
}
}
}
private void handleGroupPermissionChange(AssignedPermission permission) {
logger.debug(
"fire authorization changed event for group {}, because permission {} has changed",
@@ -207,13 +207,13 @@ public class AuthorizationChangedEventProducer {
);
fireEventForEveryUser();
}
private void handleUserPermissionChange(AssignedPermission permission) {
logger.debug(
"fire authorization changed event for user {}, because permission {} has changed",
permission.getName(), permission.getPermission()
);
fireEventForUser(permission.getName());
fireEventForUser(permission.getName());
}
/**
@@ -230,7 +230,7 @@ public class AuthorizationChangedEventProducer {
public void onEvent(GroupEvent event) {
if (event.getEventType().isPost()) {
if (isModificationEvent(event)) {
handleGroupModificationEvent((GroupModificationEvent) event);
handleGroupModificationEvent((GroupModificationEvent) event);
} else {
handleGroupEvent(event);
}
@@ -244,28 +244,28 @@ public class AuthorizationChangedEventProducer {
fireEventForEveryUser();
} else {
logger.debug(
"authorization changed event is not fired, because non relevant field of group {} has changed",
"authorization changed event is not fired, because non relevant field of group {} has changed",
group.getId()
);
}
}
private boolean isAuthorizationDataModified(Group group, Group beforeModification) {
return !group.getMembers().equals(beforeModification.getMembers());
}
private void handleGroupEvent(GroupEvent event){
logger.debug(
"fire authorization changed event, because of received group event {} for group {}",
event.getEventType(),
"fire authorization changed event, because of received group event {} for group {}",
event.getEventType(),
event.getItem().getId()
);
fireEventForEveryUser();
fireEventForEveryUser();
}
@VisibleForTesting
protected void sendEvent(AuthorizationChangedEvent event) {
ScmEventBus.getInstance().post(event);
}
}

View File

@@ -271,11 +271,6 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
}
private boolean isAdmin(User user, GroupNames groups) {
boolean admin = user.isAdmin();
if (admin) {
logger.debug("user {} is marked as admin, because of the user flag", user.getName());
return true;
}
if (isUserAdminInConfiguration(user)) {
logger.debug("user {} is marked as admin, because of the admin user configuration", user.getName());
return true;

View File

@@ -142,7 +142,6 @@ public class GitLfsITCase {
dto.setDisplayName(user.getDisplayName());
dto.setType(user.getType());
dto.setActive(user.isActive());
dto.setAdmin(user.isAdmin());
dto.setPassword(user.getPassword());
createResource(adminClient, "users")
.accept("*/*")

View File

@@ -133,7 +133,6 @@ public class UserPermissionITCase extends AbstractPermissionITCaseBase<User>
"scm-admin@scm-manager.org");
user.setPassword("hallo123");
user.setAdmin(true);
user.setType("xml");
return user;

View File

@@ -1,10 +1,10 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
@@ -13,7 +13,7 @@
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,9 +24,9 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* http://bitbucket.org/sdorra/scm-manager
*
*
*/
package sonia.scm.security;
@@ -58,18 +58,18 @@ import static org.junit.Assert.assertTrue;
/**
* Unit tests for {@link AuthorizationChangedEventProducer}.
*
*
* @author Sebastian Sdorra
*/
public class AuthorizationChangedEventProducerTest {
private StoringAuthorizationChangedEventProducer producer;
@Before
public void setUpProducer() {
producer = new StoringAuthorizationChangedEventProducer();
}
/**
* Tests {@link AuthorizationChangedEventProducer#onEvent(sonia.scm.user.UserEvent)}.
*/
@@ -79,15 +79,15 @@ public class AuthorizationChangedEventProducerTest {
User user = UserTestData.createDent();
producer.onEvent(new UserEvent(HandlerEventType.BEFORE_CREATE, user));
assertEventIsNotFired();
producer.onEvent(new UserEvent(HandlerEventType.CREATE, user));
assertUserEventIsFired("dent");
}
private void assertEventIsNotFired(){
assertNull(producer.event);
}
private void assertUserEventIsFired(String username){
assertNotNull(producer.event);
assertTrue(producer.event.isEveryUserAffected());
@@ -102,28 +102,28 @@ public class AuthorizationChangedEventProducerTest {
/**
* Tests {@link AuthorizationChangedEventProducer#onEvent(sonia.scm.user.UserEvent)} with modified user.
*/
@Test
@Test
public void testOnUserModificationEvent()
{
User user = UserTestData.createDent();
User userModified = UserTestData.createDent();
userModified.setDisplayName("Super Dent");
producer.onEvent(new UserModificationEvent(HandlerEventType.BEFORE_CREATE, userModified, user));
assertEventIsNotFired();
producer.onEvent(new UserModificationEvent(HandlerEventType.CREATE, userModified, user));
assertEventIsNotFired();
userModified.setAdmin(true);
userModified.setActive(false);
producer.onEvent(new UserModificationEvent(HandlerEventType.BEFORE_CREATE, userModified, user));
assertEventIsNotFired();
producer.onEvent(new UserModificationEvent(HandlerEventType.CREATE, userModified, user));
assertUserEventIsFired("dent");
}
/**
* Tests {@link AuthorizationChangedEventProducer#onEvent(sonia.scm.group.GroupEvent)}.
*/
@@ -133,11 +133,11 @@ public class AuthorizationChangedEventProducerTest {
Group group = new Group("xml", "base");
producer.onEvent(new GroupEvent(HandlerEventType.BEFORE_CREATE, group));
assertEventIsNotFired();
producer.onEvent(new GroupEvent(HandlerEventType.CREATE, group));
assertGlobalEventIsFired();
}
/**
* Tests {@link AuthorizationChangedEventProducer#onEvent(sonia.scm.group.GroupEvent)} with modified groups.
*/
@@ -148,15 +148,15 @@ public class AuthorizationChangedEventProducerTest {
Group modifiedGroup = new Group("xml", "base");
producer.onEvent(new GroupModificationEvent(HandlerEventType.BEFORE_MODIFY, modifiedGroup, group));
assertEventIsNotFired();
producer.onEvent(new GroupModificationEvent(HandlerEventType.MODIFY, modifiedGroup, group));
assertEventIsNotFired();
modifiedGroup.add("test");
producer.onEvent(new GroupModificationEvent(HandlerEventType.MODIFY, modifiedGroup, group));
assertGlobalEventIsFired();
}
/**
* Tests {@link AuthorizationChangedEventProducer#onEvent(sonia.scm.repository.RepositoryEvent)}.
*/
@@ -166,13 +166,13 @@ public class AuthorizationChangedEventProducerTest {
Repository repository = RepositoryTestData.createHeartOfGold();
producer.onEvent(new RepositoryEvent(HandlerEventType.BEFORE_CREATE, repository));
assertEventIsNotFired();
producer.onEvent(new RepositoryEvent(HandlerEventType.CREATE, repository));
assertGlobalEventIsFired();
}
/**
* Tests {@link AuthorizationChangedEventProducer#onEvent(sonia.scm.repository.RepositoryEvent)} with modified
* Tests {@link AuthorizationChangedEventProducer#onEvent(sonia.scm.repository.RepositoryEvent)} with modified
* repository.
*/
@Test
@@ -224,11 +224,11 @@ public class AuthorizationChangedEventProducerTest {
producer.onEvent(new RepositoryModificationEvent(HandlerEventType.CREATE, repositoryModified, repository));
assertEventIsNotFired();
}
private void resetStoredEvent(){
producer.event = null;
}
/**
* Tests {@link AuthorizationChangedEventProducer#onEvent(AssignedPermissionEvent)}.
*/
@@ -240,33 +240,33 @@ public class AuthorizationChangedEventProducerTest {
);
producer.onEvent(new AssignedPermissionEvent(HandlerEventType.BEFORE_CREATE, groupPermission));
assertEventIsNotFired();
producer.onEvent(new AssignedPermissionEvent(HandlerEventType.CREATE, groupPermission));
assertGlobalEventIsFired();
resetStoredEvent();
StoredAssignedPermission userPermission = new StoredAssignedPermission(
"123", new AssignedPermission("trillian", false, "repository:read:*")
);
producer.onEvent(new AssignedPermissionEvent(HandlerEventType.BEFORE_CREATE, userPermission));
assertEventIsNotFired();
resetStoredEvent();
producer.onEvent(new AssignedPermissionEvent(HandlerEventType.CREATE, userPermission));
assertUserEventIsFired("trillian");
}
private static class StoringAuthorizationChangedEventProducer extends AuthorizationChangedEventProducer {
private AuthorizationChangedEvent event;
@Override
protected void sendEvent(AuthorizationChangedEvent event) {
this.event = event;
}
}
}

View File

@@ -197,22 +197,6 @@ public class DefaultAuthorizationCollectorTest {
assertThat(authInfo.getObjectPermissions(), nullValue());
}
/**
* Tests {@link AuthorizationCollector#collect()} as admin.
*/
@Test
@SubjectAware(
configuration = "classpath:sonia/scm/shiro-001.ini"
)
public void testCollectAsAdmin() {
User trillian = UserTestData.createTrillian();
trillian.setAdmin(true);
authenticate(trillian, "main");
AuthorizationInfo authInfo = collector.collect();
assertIsAdmin(authInfo);
}
/**
* Tests {@link AuthorizationCollector#collect()} with repository permissions.
*/