Package ch.entwine.weblounge.security.sql.endpoint

Source Code of ch.entwine.weblounge.security.sql.endpoint.SQLDirectoryProviderEndpoint

/*
*  Weblounge: Web Content Management System
*  Copyright (c) 2003 - 2011 The Weblounge Team
*  http://entwinemedia.com/weblounge
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public License
*  as published by the Free Software Foundation; either version 2
*  of the License, or (at your option) any later version.
*
*  This program 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 Lesser General Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public License
*  along with this program; if not, write to the Free Software Foundation
*  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package ch.entwine.weblounge.security.sql.endpoint;

import ch.entwine.weblounge.common.impl.language.LanguageUtils;
import ch.entwine.weblounge.common.impl.security.PasswordEncoder;
import ch.entwine.weblounge.common.impl.security.RoleImpl;
import ch.entwine.weblounge.common.impl.security.SecurityUtils;
import ch.entwine.weblounge.common.impl.security.SystemRole;
import ch.entwine.weblounge.common.impl.security.WebloungeUserImpl;
import ch.entwine.weblounge.common.language.UnknownLanguageException;
import ch.entwine.weblounge.common.security.DigestType;
import ch.entwine.weblounge.common.security.SecurityService;
import ch.entwine.weblounge.common.security.User;
import ch.entwine.weblounge.common.security.UserExistsException;
import ch.entwine.weblounge.common.security.UserShadowedException;
import ch.entwine.weblounge.common.security.WebloungeUser;
import ch.entwine.weblounge.common.site.Site;
import ch.entwine.weblounge.common.url.UrlUtils;
import ch.entwine.weblounge.kernel.site.SiteManager;
import ch.entwine.weblounge.security.sql.SQLDirectoryProvider;
import ch.entwine.weblounge.security.sql.entities.JpaAccount;
import ch.entwine.weblounge.security.sql.entities.JpaRole;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

/**
* This class implements the <code>REST</code> endpoint to manage the SQL
* directory provider.
*/
@Path("/")
@Produces(MediaType.APPLICATION_XML)
public class SQLDirectoryProviderEndpoint {

  /** The logging facility */
  private static final Logger logger = LoggerFactory.getLogger(SQLDirectoryProviderEndpoint.class);

  /** The endpoint documentation */
  private String docs = null;

  /** The cache configuration factory */
  private SQLDirectoryProvider directory = null;

  /** The security service */
  protected SecurityService securityService = null;

  /** The sites that are online */
  protected SiteManager sites = null;

  @GET
  @Path("/")
  public Response getStatistics(@Context HttpServletRequest request) {
    Site site = getSite(request);

    try {
      StringBuilder stats = new StringBuilder();
      stats.append("<directory id=\"").append(site.getIdentifier()).append("\">");
      stats.append("<enabled>").append(directory.isSiteEnabled(site)).append("</enabled>");
      stats.append("<users>").append(directory.getAccounts(site).size()).append("</users>");
      stats.append("</directory>");
      Response response = Response.ok(stats.toString()).build();
      return response;
    } catch (Throwable t) {
      logger.warn("Error creating directory statistics: {}", t.getMessage());
      return Response.serverError().build();
    }
  }

  @PUT
  @Path("/status")
  public Response enableSite(@Context HttpServletRequest request) {
    Site site = getSite(request);

    // Make sure that the user owns the roles required for this operation
    User user = securityService.getUser();
    if (!SecurityUtils.userHasRole(user, SystemRole.SITEADMIN))
      return Response.status(Status.FORBIDDEN).build();

    // Enable login
    try {
      if (directory.isSiteEnabled(site))
        return Response.notModified().build();
      directory.enableSite(site);
      return Response.ok().build();
    } catch (Throwable t) {
      logger.warn("Error enabling site logins: {}", t.getMessage());
      return Response.serverError().build();
    }
  }

  @DELETE
  @Path("/status")
  public Response disableSite(@Context HttpServletRequest request) {
    Site site = getSite(request);

    // Make sure that the user owns the roles required for this operation
    User user = securityService.getUser();
    if (!SecurityUtils.userHasRole(user, SystemRole.SITEADMIN))
      return Response.status(Status.FORBIDDEN).build();

    // Disable login
    try {
      if (!directory.isSiteEnabled(site))
        return Response.notModified().build();
      directory.disableSite(site);
      return Response.ok().build();
    } catch (Throwable t) {
      logger.warn("Error disabling site logins: {}", t.getMessage());
      return Response.serverError().build();
    }
  }

  @POST
  @Path("/account")
  public Response createAccount(@FormParam("login") String login,
      @FormParam("password") String password, @FormParam("email") String eMail,
      @Context HttpServletRequest request) {

    // TODO: If not, return a one time pad that needs to be used when verifying
    // the e-mail

    // Check the arguments
    if (StringUtils.isBlank(login))
      return Response.status(Status.BAD_REQUEST).build();

    Response response = null;
    Site site = getSite(request);

    // Hash the password
    if (StringUtils.isNotBlank(password)) {
      logger.debug("Hashing password for user '{}@{}' using md5", login, site.getIdentifier());
      password = PasswordEncoder.encode(StringUtils.trim(password));
    }

    // Create the user
    try {
      JpaAccount account = directory.addAccount(site, login, password);
      account.setEmail(StringUtils.trimToNull(eMail));
      directory.updateAccount(account);
      response = Response.created(new URI(UrlUtils.concat(request.getRequestURL().toString(), account.getLogin()))).build();
    } catch (UserExistsException e) {
      logger.warn("Error creating account: {}", e.getMessage());
      return Response.status(Status.CONFLICT).build();
    } catch (UserShadowedException e) {
      logger.warn("Error creating account: {}", e.getMessage());
      return Response.status(Status.CONFLICT).build();
    } catch (Throwable t) {
      logger.warn("Error creating account: {}", t.getMessage());
      response = Response.serverError().build();
    }
    return response;
  }

  @GET
  @Path("/account/{login}")
  public Response getAccount(@PathParam("login") String login,
      @Context HttpServletRequest request) {
    Site site = getSite(request);

    JpaAccount account = null;
    try {
      account = directory.getAccount(site, login);
    } catch (Throwable t) {
      logger.warn("Error accessing account '{}': {}", login, t.getMessage());
      throw new WebApplicationException();
    }

    if (account == null)
      throw new WebApplicationException(Status.NOT_FOUND);

    WebloungeUser wu = new WebloungeUserImpl(login, directory.getIdentifier());
    wu.setFirstName(account.getFirstname());
    wu.setLastName(account.getLastname());
    wu.setEmail(account.getEmail());
    wu.setInitials(account.getInitials());
    wu.setLastLogin(account.getLastLoginDate(), account.getLastLoginFrom());
    wu.setChallenge(account.getChallenge());
    if (account.getLanguage() != null)
      wu.setLanguage(LanguageUtils.getLanguage(account.getLanguage()));
    if (account.getResponse() != null)
      wu.setResponse(account.getResponse().getBytes(Charset.forName("utf-8")), DigestType.md5);
    for (JpaRole r : account.getRoles()) {
      wu.addPublicCredentials(new RoleImpl(r.getContext(), r.getRolename()));
    }

    return Response.ok(wu.toXml()).build();
  }

  @GET
  @Path("/account/{login}/activate")
  public Response activateAccount(@PathParam("login") String login,
      @QueryParam("activation") String activation,
      @Context HttpServletRequest request) {
    Site site = getSite(request);
    try {
      boolean success = directory.activateAccount(site, login, activation);
      return (success) ? Response.ok().build() : Response.status(Status.UNAUTHORIZED).build();
    } catch (Throwable t) {
      logger.warn("Error activating account '{}': {}", login, t.getMessage());
      return Response.serverError().build();
    }
  }

  @PUT
  @Path("/account/{id}")
  public Response updateAccount(@PathParam("id") String login,
      @FormParam("password") String password,
      @FormParam("firstname") String firstname,
      @FormParam("lastname") String lastname,
      @FormParam("initials") String initials, @FormParam("email") String email,
      @FormParam("language") String language,
      @FormParam("challenge") String challenge,
      @FormParam("response") String response,
      @Context HttpServletRequest request) {

    // Make sure that the user owns the roles required for this operation
    User user = securityService.getUser();
    if (!SecurityUtils.userHasRole(user, SystemRole.SITEADMIN) && !user.getLogin().equals(login))
      return Response.status(Status.FORBIDDEN).build();

    JpaAccount account = null;
    Site site = getSite(request);
    try {
      account = directory.getAccount(site, login);
      if (account == null)
        return Response.status(Status.NOT_FOUND).build();

      // Hash the password
      if (StringUtils.isNotBlank(password)) {
        logger.debug("Hashing password for user '{}@{}' using md5", login, site.getIdentifier());
        String digestPassword = PasswordEncoder.encode(StringUtils.trim(password));
        account.setPassword(digestPassword);
      }

      account.setFirstname(StringUtils.trimToNull(firstname));
      account.setLastname(StringUtils.trimToNull(lastname));
      account.setInitials(StringUtils.trimToNull(initials));
      account.setEmail(StringUtils.trimToNull(email));

      // The language
      if (StringUtils.isNotBlank(language)) {
        try {
          account.setLanguage(LanguageUtils.getLanguage(language));
        } catch (UnknownLanguageException e) {
          return Response.status(Status.BAD_REQUEST).build();
        }
      } else {
        account.setLanguage(null);
      }

      // Hash the response
      if (StringUtils.isNotBlank(response)) {
        logger.debug("Hashing response for user '{}@{}' using md5", login, site.getIdentifier());
        String digestResponse = PasswordEncoder.encode(StringUtils.trim(response));
        account.setResponse(digestResponse);
      }

      directory.updateAccount(account);
      return Response.ok().build();
    } catch (Throwable t) {
      return Response.serverError().build();
    }
  }

  @PUT
  @Path("/account/{id}/password")
  public Response updateAccountPassword(@PathParam("id") String login,
      @FormParam("password") String password,
      @Context HttpServletRequest request) {

    // Make sure that the user owns the roles required for this operation
    User user = securityService.getUser();
    if (!SecurityUtils.userHasRole(user, SystemRole.SITEADMIN) && !user.getLogin().equals(login))
      return Response.status(Status.FORBIDDEN).build();

    JpaAccount account = null;
    Site site = getSite(request);
    try {
      account = directory.getAccount(site, login);
      if (account == null)
        return Response.status(Status.NOT_FOUND).build();

      // Hash the password
      if (StringUtils.isNotBlank(password)) {
        logger.debug("Hashing password for user '{}@{}' using md5", login, site.getIdentifier());
        String digestPassword = PasswordEncoder.encode(StringUtils.trim(password));
        account.setPassword(digestPassword);
      } else {
        account.setPassword(null);
      }

      directory.updateAccount(account);
      return Response.ok().build();
    } catch (Throwable t) {
      return Response.serverError().build();
    }
  }

  @PUT
  @Path("/account/{id}/challenge")
  public Response updateAccountChallenge(@PathParam("id") String login,
      @FormParam("challenge") String challenge,
      @FormParam("response") String response,
      @Context HttpServletRequest request) {

    // Make sure that the user owns the roles required for this operation
    User user = securityService.getUser();
    if (!SecurityUtils.userHasRole(user, SystemRole.SITEADMIN) && !user.getLogin().equals(login))
      return Response.status(Status.FORBIDDEN).build();

    JpaAccount account = null;
    Site site = getSite(request);
    try {
      account = directory.getAccount(site, login);
      if (account == null)
        return Response.status(Status.NOT_FOUND).build();

      // Set the challenge
      account.setChallenge(StringUtils.trimToNull(challenge));

      // Hash the response
      if (StringUtils.isNotBlank(response)) {
        logger.debug("Hashing response for user '{}@{}' using md5", login, site.getIdentifier());
        String digestResponse = PasswordEncoder.encode(StringUtils.trim(response));
        account.setResponse(digestResponse);
      } else {
        account.setResponse(response);
      }

      directory.updateAccount(account);
      return Response.ok().build();
    } catch (Throwable t) {
      return Response.serverError().build();
    }
  }

  @DELETE
  @Path("/account/{id}")
  public Response deleteAccount(@PathParam("id") String login,
      @Context HttpServletRequest request) {

    // Make sure that the user owns the roles required for this operation
    User user = securityService.getUser();
    if (!SecurityUtils.userHasRole(user, SystemRole.SITEADMIN) && !user.getLogin().equals(login))
      return Response.status(Status.FORBIDDEN).build();

    Site site = getSite(request);
    try {
      JpaAccount account = directory.getAccount(site, login);
      if (account == null)
        return Response.status(Status.NOT_FOUND).build();

      directory.removeAccount(site, login);
      return Response.ok().build();
    } catch (Throwable t) {
      logger.warn("Error removing account '{}': {}", login, t.getMessage());
      return Response.serverError().build();
    }
  }

  @PUT
  @Path("/account/{id}/status")
  public Response enableAccount(@PathParam("id") String login,
      @Context HttpServletRequest request) {

    // Make sure that the user owns the roles required for this operation
    User user = securityService.getUser();
    if (!SecurityUtils.userHasRole(user, SystemRole.SITEADMIN))
      return Response.status(Status.FORBIDDEN).build();

    JpaAccount account = null;
    Site site = getSite(request);
    try {
      account = directory.getAccount(site, login);
      if (account == null)
        return Response.status(Status.NOT_FOUND).build();
      if (account.isEnabled())
        return Response.status(Status.NOT_MODIFIED).build();

      directory.enableAccount(site, login);
      return Response.ok().build();
    } catch (Throwable t) {
      logger.warn("Error enabling account '{}': {}", login, t.getMessage());
      return Response.serverError().build();
    }
  }

  @DELETE
  @Path("/account/{id}/status")
  public Response disableAccount(@PathParam("id") String login,
      @Context HttpServletRequest request) {

    // Make sure that the user owns the roles required for this operation
    User user = securityService.getUser();
    if (!SecurityUtils.userHasRole(user, SystemRole.SITEADMIN))
      return Response.status(Status.FORBIDDEN).build();

    JpaAccount account = null;
    Site site = getSite(request);
    try {
      account = directory.getAccount(site, login);
      if (account == null)
        return Response.status(Status.NOT_FOUND).build();
      if (!account.isEnabled())
        return Response.status(Status.NOT_MODIFIED).build();

      directory.disableAccount(site, login);
      return Response.ok().build();
    } catch (Throwable t) {
      logger.warn("Error disabling account '{}': {}", login, t.getMessage());
      return Response.serverError().build();
    }
  }

  @POST
  @Path("/account/{id}/roles/{context}")
  public Response addRole(@PathParam("id") String login,
      @PathParam("context") String context, @FormParam("role") String role,
      @Context HttpServletRequest request) {

    // Make sure that the user owns the roles required for this operation
    User user = securityService.getUser();
    if (!SecurityUtils.userHasRole(user, SystemRole.SITEADMIN))
      return Response.status(Status.FORBIDDEN).build();

    // Make sure a role has been provided as part of the request
    if (StringUtils.isBlank(role))
      return Response.status(Status.BAD_REQUEST).build();

    JpaAccount account = null;
    Site site = getSite(request);
    try {
      account = directory.getAccount(site, login);
      if (account == null)
        return Response.status(Status.NOT_FOUND).build();

      if (account.hasRole(context, role))
        return Response.status(Status.NOT_MODIFIED).build();

      account.addRole(context, role);
      directory.updateAccount(account);
      return Response.ok().build();
    } catch (Throwable t) {
      logger.warn("Error adding role '{}:{}' to account {}: {}", new String[] {
          context,
          role,
          login,
          t.getMessage() });
      return Response.serverError().build();
    }
  }

  @DELETE
  @Path("/account/{id}/roles/{context}")
  public Response removeRole(@PathParam("id") String login,
      @PathParam("context") String context, @FormParam("role") String role,
      @Context HttpServletRequest request) {

    // Make sure that the user owns the roles required for this operation
    User user = securityService.getUser();
    if (!SecurityUtils.userHasRole(user, SystemRole.SITEADMIN))
      return Response.status(Status.FORBIDDEN).build();

    // Make sure a role has been provided as part of the request
    if (StringUtils.isBlank(role))
      return Response.status(Status.BAD_REQUEST).build();

    JpaAccount account = null;
    Site site = getSite(request);
    try {
      account = directory.getAccount(site, login);
      if (account == null)
        return Response.status(Status.NOT_FOUND).build();

      if (!account.hasRole(context, role))
        return Response.status(Status.NOT_MODIFIED).build();

      account.removeRole(context, role);
      directory.updateAccount(account);
      return Response.ok().build();
    } catch (Throwable t) {
      logger.warn("Error adding role '{}:{}' to account: {}", new String[] {
          context,
          role,
          login,
          t.getMessage() });
      return Response.serverError().build();
    }
  }

  /**
   * Returns the endpoint documentation.
   *
   * @return the endpoint documentation
   */
  @GET
  @Path("/docs")
  @Produces(MediaType.TEXT_HTML)
  public String getDocumentation(@Context HttpServletRequest request) {
    if (docs == null) {
      String docsPath = request.getRequestURI();
      String docsPathExtension = request.getPathInfo();
      String servicePath = request.getRequestURI().substring(0, docsPath.length() - docsPathExtension.length());
      docs = SQLDirectoryProviderEndpointDocs.createDocumentation(servicePath);
    }
    return docs;
  }

  /**
   * Extracts the site from the request and returns it. If the site is not found
   * or it's not running, a corresponding <code>WebApplicationException</code>
   * is thrown.
   *
   * @param request
   *          the http request
   * @return the site
   * @throws WebApplicationException
   *           if the site is not found or is not running
   */
  protected Site getSite(HttpServletRequest request)
      throws WebApplicationException {
    URL url = UrlUtils.toURL(request, false, false);
    Site site = sites.findSiteByURL(url);
    if (site == null) {
      throw new WebApplicationException(Status.NOT_FOUND);
    } else if (!site.isOnline()) {
      throw new WebApplicationException(Status.SERVICE_UNAVAILABLE);
    }
    return site;
  }

  /**
   * Callback for OSGi to set the site manager.
   *
   * @param siteManager
   *          the site manager
   */
  void setSiteManager(SiteManager siteManager) {
    this.sites = siteManager;
  }

  /**
   * Callback from the OSGi declarative services environment that will pass in a
   * reference to the directory provider.
   *
   * @param directoryProvider
   *          the sql directory provider
   */
  void setDiretoryProvider(SQLDirectoryProvider directoryProvider) {
    this.directory = directoryProvider;
  }

  /**
   * Callback from OSGi to set the security service.
   *
   * @param securityService
   *          the security service
   */
  void setSecurityService(SecurityService securityService) {
    this.securityService = securityService;
  }

  /**
   * {@inheritDoc}
   *
   * @see java.lang.Object#toString()
   */
  @Override
  public String toString() {
    return "SQL directory rest endpoint";
  }

}
TOP

Related Classes of ch.entwine.weblounge.security.sql.endpoint.SQLDirectoryProviderEndpoint

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.