Package controllers

Source Code of controllers.UsersController

/*
* Copyright 2013 TORCH UG
*
* This file is part of Graylog2.
*
* Graylog2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Graylog2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Graylog2.  If not, see <http://www.gnu.org/licenses/>.
*/
package controllers;

import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import lib.BreadcrumbList;
import lib.security.RestPermissions;
import org.apache.shiro.subject.Subject;
import org.graylog2.restclient.lib.APIException;
import org.graylog2.restclient.lib.ApiClient;
import org.graylog2.restclient.lib.DateTools;
import org.graylog2.restclient.lib.Tools;
import org.graylog2.restclient.models.PermissionsService;
import org.graylog2.restclient.models.StreamService;
import org.graylog2.restclient.models.User;
import org.graylog2.restclient.models.UserService;
import org.graylog2.restclient.models.api.requests.ChangePasswordRequest;
import org.graylog2.restclient.models.api.requests.ChangeUserRequest;
import org.graylog2.restclient.models.api.requests.ChangeUserRequestForm;
import org.graylog2.restclient.models.api.requests.CreateUserRequestForm;
import org.graylog2.restclient.models.dashboards.DashboardService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import play.data.DynamicForm;
import play.data.Form;
import play.libs.Json;
import play.mvc.BodyParser;
import play.mvc.Result;
import views.helpers.Permissions;
import views.html.system.users.edit;
import views.html.system.users.new_user;
import views.html.system.users.show;

import javax.annotation.Nullable;
import javax.inject.Inject;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import static lib.security.RestPermissions.DASHBOARDS_EDIT;
import static lib.security.RestPermissions.DASHBOARDS_READ;
import static lib.security.RestPermissions.STREAMS_EDIT;
import static lib.security.RestPermissions.STREAMS_READ;
import static lib.security.RestPermissions.USERS_LIST;
import static lib.security.RestPermissions.USERS_PERMISSIONSEDIT;
import static views.helpers.Permissions.isPermitted;

public class UsersController extends AuthenticatedController {
    private static final Logger log = LoggerFactory.getLogger(UsersController.class);

    private static final Form<CreateUserRequestForm> createUserForm = Form.form(CreateUserRequestForm.class);
    private static final Form<ChangeUserRequestForm> changeUserForm = Form.form(ChangeUserRequestForm.class);
    private static final Form<ChangePasswordRequest> changePasswordForm = Form.form(ChangePasswordRequest.class);

    private final UserService userService;
    private final PermissionsService permissionsService;
    private final StreamService streamService;
    private final DashboardService dashboardService;

    @Inject
    public UsersController(UserService userService, PermissionsService permissionsService, StreamService streamService, DashboardService dashboardService) {
        this.userService = userService;
        this.permissionsService = permissionsService;
        this.streamService = streamService;
        this.dashboardService = dashboardService;
    }

    public Result index() {
        final List<User> allUsers = isPermitted(USERS_LIST) ? userService.all() : Lists.newArrayList(currentUser());
        final List<String> permissions = permissionsService.all();
        return ok(views.html.system.users.index.render(currentUser(), breadcrumbs(), allUsers, permissions));
    }

    public Result show(String username) {
        final User user = userService.load(username);
        if (user == null) {
            String message = "User not found! Maybe it has been deleted.";
            return status(404, views.html.errors.error.render(message, new RuntimeException(), request()));
        }

        BreadcrumbList bc = breadcrumbs();
        bc.addCrumb(user.getFullName(), routes.UsersController.show(username));

        return ok(show.render(user, currentUser(), bc));
    }

    public Result newUserForm() {
        BreadcrumbList bc = breadcrumbs();
        bc.addCrumb("New", routes.UsersController.newUserForm());

        final List<String> permissions = permissionsService.all();
        try {
            return ok(new_user.render(
                    createUserForm,
                    currentUser(),
                    permissions,
                    ImmutableSet.<String>of(),
                    DateTools.getGroupedTimezoneIds().asMap(),
                    DateTools.getApplicationTimeZone(),
                    streamService.all(),
                    bc));
        } catch (IOException e) {
            return status(504, views.html.errors.error.render(ApiClient.ERROR_MSG_IO, e, request()));
        } catch (APIException e) {
            String message = "Could not fetch streams. We expected HTTP 200, but got a HTTP " + e.getHttpCode() + ".";
            return status(504, views.html.errors.error.render(message, e, request()));
        }
    }

    public Result editUserForm(String username) {
        BreadcrumbList bc = breadcrumbs();
        bc.addCrumb("Edit " + username, routes.UsersController.editUserForm(username));

        User user = userService.load(username);
        final Form<ChangeUserRequestForm> form = changeUserForm.fill(new ChangeUserRequestForm(user));
        boolean requiresOldPassword = checkRequireOldPassword(username);
        try {
            return ok(edit.render(
                            form,
                            username,
                            currentUser(),
                            user,
                            requiresOldPassword,
                            permissionsService.all(),
                            ImmutableSet.copyOf(user.getPermissions()),
                            DateTools.getGroupedTimezoneIds().asMap(),
                            streamService.all(),
                            dashboardService.getAll(),
                            bc)
            );
        } catch (IOException e) {
            return status(504, views.html.errors.error.render(ApiClient.ERROR_MSG_IO, e, request()));
        } catch (APIException e) {
            String message = "Could not fetch streams. We expected HTTP 200, but got a HTTP " + e.getHttpCode() + ".";
            return status(504, views.html.errors.error.render(message, e, request()));
        }
    }

    public Result loadUser(String username) {
        User user = userService.load(username);
        if (user != null) {
            Map<String, Object> result = Maps.newHashMap();
            result.put("preferences", initDefaultPreferences(user.getPreferences()));
            // TODO: there is more than preferences
            return ok(Json.toJson(result));
        } else {
            return notFound();
        }
    }

    @BodyParser.Of(BodyParser.Json.class)
    public Result saveUserPreferences(String username) throws IOException {
        Map<String, Object> preferences = Json.fromJson(request().body().asJson(), Map.class);
        if (userService.savePreferences(username, normalizePreferences(preferences))) {
            return ok();
        } else {
            // TODO: Really?
            return notFound();
        }
    }

    private Map<String, Object> initDefaultPreferences(Map<String, Object> preferences) {
        Map<String, Object> effectivePreferences = Maps.newHashMap();
        // TODO: Move defaults into a static map once we at least have a second preference
        effectivePreferences.put("updateUnfocussed", false);
        if (preferences != null) {
            effectivePreferences.putAll(preferences);
        }
        return effectivePreferences;
    }

    private Map<String, Object> normalizePreferences(Map<String, Object> preferences) {
        Map<String, Object> normalizedPreferences = Maps.newHashMap();
        // TODO: Move types into a static map once we at least have a second preference
        for (Map.Entry<String, Object> preference : preferences.entrySet()) {
            if (preference.getKey().equals("updateUnfocussed")) {
                final Object value = preference.getValue();
                final Object normalizedValue;
                if (value instanceof Boolean) {
                    normalizedValue = value;
                } else {
                    normalizedValue = Boolean.valueOf(value.toString());
                }
                normalizedPreferences.put(preference.getKey(), normalizedValue);
            }
        }
        return normalizedPreferences;
    }

    public Result create() {
        Form<CreateUserRequestForm> createUserRequestForm = Tools.bindMultiValueFormFromRequest(CreateUserRequestForm.class);
        final CreateUserRequestForm request = createUserRequestForm.get();

        if (createUserRequestForm.hasErrors()) {
            BreadcrumbList bc = breadcrumbs();
            bc.addCrumb("Create new", routes.UsersController.newUserForm());
            final List<String> permissions = permissionsService.all();
            try {
                return badRequest(new_user.render(
                        createUserRequestForm,
                        currentUser(),
                        permissions,
                        ImmutableSet.copyOf(request.permissions),
                        DateTools.getGroupedTimezoneIds().asMap(),
                        DateTools.getApplicationTimeZone(),
                        streamService.all(),
                        bc));
            } catch (IOException e) {
                return status(504, views.html.errors.error.render(ApiClient.ERROR_MSG_IO, e, request()));
            } catch (APIException e) {
                String message = "Could not fetch streams. We expected HTTP 200, but got a HTTP " + e.getHttpCode() + ".";
                return status(504, views.html.errors.error.render(message, e, request()));
            }
        }
        if (request.admin) {
            request.permissions = Lists.newArrayList("*");
        } else {
            request.permissions = permissionsService.readerPermissions(request.username);
        }

        if (!userService.create(request.toApiRequest())) {
            flash("error", "Could not create user due to an internal error.");
        }
        return redirect(routes.UsersController.index());
    }

    public Result delete(String username) {
        userService.delete(username);
        return redirect(routes.UsersController.index());
    }

    public Result isUniqueUsername(String username) {
//        if (LocalAdminUser.getInstance().getName().equals(username)) {
//            return noContent();
//        }
        if (userService.load(username) == null) {
            return notFound();
        } else {
            return noContent();
        }
    }

    public Result saveChanges(String username) {
        final Form<ChangeUserRequestForm> requestForm = Form.form(ChangeUserRequestForm.class).bindFromRequest();
        final User user = userService.load(username);

        if (requestForm.hasErrors()) {
            final BreadcrumbList bc = new BreadcrumbList();
            bc.addCrumb("System", routes.SystemController.index(0));
            bc.addCrumb("Users", routes.UsersController.index());
            bc.addCrumb("Edit " + username, routes.UsersController.editUserForm(username));

            final List<String> all = permissionsService.all();
            boolean requiresOldPassword = checkRequireOldPassword(username);

            try {
                return badRequest(edit.render(
                        requestForm,
                        username,
                        currentUser(),
                        user,
                        requiresOldPassword,
                        all,
                        ImmutableSet.copyOf(requestForm.get().permissions),
                        DateTools.getGroupedTimezoneIds().asMap(),
                        streamService.all(),
                        dashboardService.getAll(),
                        bc));
            } catch (IOException e) {
                return status(504, views.html.errors.error.render(ApiClient.ERROR_MSG_IO, e, request()));
            } catch (APIException e) {
                String message = "Could not fetch streams. We expected HTTP 200, but got a HTTP " + e.getHttpCode() + ".";
                return status(504, views.html.errors.error.render(message, e, request()));
            }
        }

        final ChangeUserRequestForm formData = requestForm.get();
        // translate session timeout value from form fields to millis
        if (!formData.session_timeout_never) {
            TimeUnit timeoutUnit;
            if (formData.timeout_unit != null) {
                try {
                    timeoutUnit = TimeUnit.valueOf(formData.timeout_unit.toUpperCase());
                    formData.sessionTimeoutMs = timeoutUnit.toMillis(formData.timeout);
                } catch (IllegalArgumentException e) {
                    log.warn("Unknown value for session timeout unit. Cannot set session timeout value.", e);
                }
            }
        } else {
            formData.sessionTimeoutMs = -1; // which translates to "never".
        }
        Set<String> permissions = Sets.newHashSet(user.getPermissions());
        // TODO this does not handle combined permissions like streams:edit,read:1,2 !
        // remove all streams:edit, streams:read permissions and add the ones from the form back.

        permissions = Sets.newHashSet(Sets.filter(permissions, new Predicate<String>() {
            @Override
            public boolean apply(@Nullable String input) {
                return (input != null) &&
                        !(input.startsWith(STREAMS_READ) || input.startsWith(STREAMS_EDIT) ||
                                input.startsWith(DASHBOARDS_READ) || input.startsWith(DASHBOARDS_EDIT));
            }
        }));
        for (String streampermission : formData.streampermissions) {
            permissions.add(RestPermissions.STREAMS_READ + ":" + streampermission);
        }
        for (String streameditpermission : formData.streameditpermissions) {
            permissions.add(RestPermissions.STREAMS_EDIT + ":" + streameditpermission);
        }
        for (String dashboardpermission : formData.dashboardpermissions) {
            permissions.add(RestPermissions.DASHBOARDS_READ + ":" + dashboardpermission);
        }
        for (String dashboardeditpermissions : formData.dashboardeditpermissions) {
            permissions.add(RestPermissions.DASHBOARDS_EDIT + ":" + dashboardeditpermissions);
        }
        final ChangeUserRequest changeRequest = formData.toApiRequest();
        changeRequest.permissions = Lists.newArrayList(permissions);
        user.update(changeRequest);

        return redirect(routes.UsersController.index());
    }

    private boolean checkRequireOldPassword(String username) {
        boolean requiresOldPassword = true;
        final User currentUser = currentUser();
        final Subject subject = currentUser.getSubject();
        final String currentUserName = currentUser.getName();
        if (subject.isPermitted("users:passwordchange:*")) {
            // if own account, require old password, otherwise don't require it
            requiresOldPassword = currentUserName.equals(username);
        }
        return requiresOldPassword;
    }

    public Result changePassword(String username) {
        final Form<ChangePasswordRequest> requestForm = changePasswordForm.bindFromRequest("old_password", "password");

        final ChangePasswordRequest request = requestForm.get();
        final User user = userService.load(username);

        if (checkRequireOldPassword(username) && request.old_password == null) {
            requestForm.reject("Old password is required.");
        }
        if (requestForm.hasErrors() || !user.updatePassword(request)) {
            flash("error", "Could not update the password.");
            return redirect(routes.UsersController.editUserForm(username));
        }

        flash("success", "Successfully changed the password for user " + user.getFullName());
        return redirect(routes.UsersController.index());
    }

    public Result resetPermissions(String username) {
        final DynamicForm requestForm = Form.form().bindFromRequest();

        boolean isAdmin = false;
        final String field = requestForm.get("permissiontype");
        if (field != null && field.equalsIgnoreCase("admin")) {
            isAdmin = true;
        }
        final User user = userService.load(username);

        if (!Permissions.isPermitted(USERS_PERMISSIONSEDIT) || user.isReadonly()) {
            flash("error", "Unable to reset permissions!");
            return redirect(routes.UsersController.editUserForm(username));
        }

        final ChangeUserRequest changeRequest = new ChangeUserRequest(user);
        if (isAdmin) {
            changeRequest.permissions = Lists.newArrayList("*");
        } else {
            changeRequest.permissions = permissionsService.readerPermissions(username);
        }
        final boolean success = user.update(changeRequest);
        if (success) {
            flash("success", "Successfully reset permission for " + user.getFullName() + " to " + (isAdmin ? "administrator" : "reader") + " permissions.");
        } else {
            flash("error", "Unable to reset permissions for user " + user.getFullName());
        }
        return redirect(routes.UsersController.editUserForm(username));
    }

    private static BreadcrumbList breadcrumbs() {
        BreadcrumbList bc = new BreadcrumbList();
        bc.addCrumb("System", routes.SystemController.index(0));
        bc.addCrumb("Users", routes.UsersController.index());
        return bc;
    }
}
TOP

Related Classes of controllers.UsersController

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.