All Downloads are FREE. Search and download functionalities are using the official Maven repository.

software.coolstuff.springframework.owncloud.service.impl.rest.AbstractOwncloudRestServiceImpl Maven / Gradle / Ivy

There is a newer version: 1.5.0
Show newest version
/*-
 * #%L
 * owncloud-spring-boot-starter
 * %%
 * Copyright (C) 2016 - 2017 by the original Authors
 * %%
 * This program 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.
 * 
 * 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public
 * License along with this program.  If not, see
 * .
 * #L%
 */
package software.coolstuff.springframework.owncloud.service.impl.rest;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.http.*;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import software.coolstuff.springframework.owncloud.exception.OwncloudStatusException;
import software.coolstuff.springframework.owncloud.exception.auth.OwncloudInvalidAuthenticationObjectException;
import software.coolstuff.springframework.owncloud.model.OwncloudUserDetails;
import software.coolstuff.springframework.owncloud.service.impl.OwncloudUtils;

import javax.annotation.PostConstruct;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Map;

import static lombok.AccessLevel.PROTECTED;

@RequiredArgsConstructor(access = PROTECTED)
@Slf4j
abstract class AbstractOwncloudRestServiceImpl implements OwncloudRestService {

  private static final String DEFAULT_PATH = "/ocs/v1.php";
  private static final String AUTHORIZATION_METHOD_PREFIX = "Basic ";

  private final RestTemplateBuilder restTemplateBuilder;
  private final OwncloudRestProperties properties;
  private final ResponseErrorHandler responseErrorHandler;

  @Getter(PROTECTED)
  MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
  private RestTemplate restTemplate;

  protected AbstractOwncloudRestServiceImpl(RestTemplateBuilder builder, OwncloudRestProperties properties) {
    this(builder, properties, new DefaultOwncloudResponseErrorHandler(SpringSecurityMessageSource.getAccessor()));
  }

  @PostConstruct
  public void afterPropertiesSet() throws Exception {
    URL locationURL = OwncloudRestUtils.checkAndConvertLocation(properties.getLocation());
    configureRestTemplate(locationURL);
  }

  private void configureRestTemplate(URL locationURL) throws MalformedURLException {
    String rootUri = OwncloudRestUtils.appendDefaultPath(locationURL, DEFAULT_PATH);
    log.info("Create the REST-Template to URI {} to be used with the authenticated User", rootUri);
    restTemplate = restTemplateBuilder
        .additionalMessageConverters(new FormHttpMessageConverter())
        .errorHandler(responseErrorHandler)
        .rootUri(rootUri)
        .build();
    Validate.notNull(restTemplate);
  }

  @Override
  public RestTemplate getRestTemplate() {
    return restTemplate;
  }

  protected HttpHeaders prepareHeadersWithBasicAuthorization() {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    if (OwncloudUtils.isAuthenticationClassNotSupported(authentication.getClass())) {
      throw new OwncloudInvalidAuthenticationObjectException(authentication, UsernamePasswordAuthenticationToken.class);
    }
    return OwncloudRestUtils.addAuthorizationHeader(authentication);
  }

  protected String getLocation() {
    return properties.getLocation();
  }

  protected HttpEntity emptyEntity(String username, String password) {
    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
    HttpHeaders headers = OwncloudRestUtils.addAuthorizationHeader(authenticationToken);
    return new HttpEntity<>(headers);
  }

  protected HttpEntity emptyEntity() {
    return new HttpEntity<>(prepareHeadersWithBasicAuthorization());
  }

  protected HttpEntity> multiValuedEntity(Map> data) {
    HttpHeaders headers = prepareHeadersWithBasicAuthorization();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    return new HttpEntity<>(new LinkedMultiValueMap<>(data), headers);
  }

  protected  T exchange(
      String url,
      HttpMethod method,
      HttpEntity httpEntity,
      Class clazz,
      Object... urlVariables) {
    return exchange(url, method, httpEntity, clazz, this::checkFailure, urlVariables);
  }

  protected  T exchange(
      String url,
      HttpMethod method,
      HttpEntity httpEntity,
      Class clazz,
      OwncloudResponseStatusChecker statusChecker,
      Object... urlVariables) {
    log.trace("Exchange Data by a {} Request with URL {}. Requested Class of returned Data is {}", method, url, clazz);
    ResponseEntity response = restTemplate.exchange(url, method, httpEntity, clazz, urlVariables);
    T result = response.getBody();
    log.trace("Returned Meta-Data: {}", result.getMeta());
    log.debug("Check the returned Meta-Data for Errors");
    String authorizationUser = getAuthorizationUserFromHeaders(httpEntity.getHeaders());
    statusChecker.checkForFailure(authorizationUser, url, result.getMeta());
    return result;
  }

  protected String getAuthorizationUserFromHeaders(HttpHeaders headers) {
    Validate.notNull(headers);

    List authorizations = headers.get(HttpHeaders.AUTHORIZATION);
    if (CollectionUtils.isEmpty(authorizations)) {
      return null;
    }

    String encodedCredentials = authorizations.get(0);
    if (StringUtils.startsWith(encodedCredentials, AUTHORIZATION_METHOD_PREFIX)) {
      encodedCredentials = StringUtils.substring(encodedCredentials, AUTHORIZATION_METHOD_PREFIX.length());
    }
    final byte[] rawDecodedCredentials = Base64.getDecoder().decode(encodedCredentials.getBytes());
    final String decodedCredentials = new String(rawDecodedCredentials);
    if (!StringUtils.contains(decodedCredentials, ':')) {
      return null;
    }
    return StringUtils.split(decodedCredentials, ':')[0];
  }

  protected void checkFailure(String username, String uri, Ocs.Meta meta) throws OwncloudStatusException {
    if ("ok".equals(meta.getStatus())) {
      return;
    }

    String exceptionMessage;
    switch (meta.getStatuscode()) {
      case 997:
        exceptionMessage = String.format("User %s is not authorized to access Resource %s", username, uri);
        log.warn("Error 997: {}", exceptionMessage);
        throw new AccessDeniedException(exceptionMessage);
      case 998:
        log.error("Error 998: {}", meta.getMessage());
        throw new UsernameNotFoundException(meta.getMessage());
      default:
        exceptionMessage = String.format("Unknown Error Code %d. Reason: %s", meta.getStatuscode(), StringUtils.defaultIfEmpty(meta.getMessage(), ""));
        log.error(exceptionMessage);
        throw new IllegalStateException(exceptionMessage);
    }
  }

  protected OwncloudUserDetails convert(String username, Ocs.User user, Ocs.Groups groupsFromBackend) {
    List authorities = new ArrayList<>();
    if (isAnyOwncloudGroupAvailable(groupsFromBackend)) {
      log.trace("Put {} Owncloud-Group(s) into the Authorities- and Group-List");
      groupsFromBackend.getData().getGroups().stream()
                       .map(Ocs.Groups.Data.Group::getGroup)
                       .map(SimpleGrantedAuthority::new)
                       .forEach(authorities::add);
    }

    log.debug("Convert User {} from {} to {}", username, user.getClass(), OwncloudUserDetails.class);
    return OwncloudUserDetails.builder()
                              .username(username)
                              .enabled(user.getData().isEnabled())
                              .displayname(user.getData().getDisplayname())
                              .email(user.getData().getEmail())
                              .quota(user.getData().getQuota().getTotal())
                              .authorities(authorities)
                              .build();
  }

  private boolean isAnyOwncloudGroupAvailable(Ocs.Groups groups) {
    return groups != null && groups.getData() != null && groups.getData().getGroups() != null;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy