org avatar changing

This commit is contained in:
Jake Potrebic 2020-09-03 21:46:50 -07:00
parent 1a3af79777
commit b80a2b2323
No known key found for this signature in database
GPG Key ID: 7C58557EC9C421F8
3 changed files with 99 additions and 4 deletions

View File

@ -1,5 +1,6 @@
package io.papermc.hangar.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.papermc.hangar.config.hangar.HangarConfig;
import io.papermc.hangar.db.model.OrganizationsTable;
import io.papermc.hangar.db.model.UserOrganizationRolesTable;
@ -7,6 +8,7 @@ import io.papermc.hangar.db.model.UsersTable;
import io.papermc.hangar.model.NotificationType;
import io.papermc.hangar.model.Role;
import io.papermc.hangar.model.viewhelpers.UserData;
import io.papermc.hangar.service.AuthenticationService;
import io.papermc.hangar.service.NotificationService;
import io.papermc.hangar.service.OrgFactory;
import io.papermc.hangar.service.OrgService;
@ -32,6 +34,7 @@ import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -39,6 +42,7 @@ import java.util.Map;
@Controller
public class OrgController extends HangarController {
private final AuthenticationService authenticationService;
private final OrgService orgService;
private final OrgFactory orgFactory;
private final UserService userService;
@ -48,7 +52,8 @@ public class OrgController extends HangarController {
private final RouteHelper routeHelper;
@Autowired
public OrgController(OrgService orgService, OrgFactory orgFactory, UserService userService, RoleService roleService, NotificationService notificationService, HangarConfig hangarConfig, RouteHelper routeHelper) {
public OrgController(AuthenticationService authenticationService, OrgService orgService, OrgFactory orgFactory, UserService userService, RoleService roleService, NotificationService notificationService, HangarConfig hangarConfig, RouteHelper routeHelper) {
this.authenticationService = authenticationService;
this.orgService = orgService;
this.orgFactory = orgFactory;
this.userService = userService;
@ -123,8 +128,16 @@ public class OrgController extends HangarController {
@Secured("ROLE_USER")
@GetMapping("/organizations/{organization}/settings/avatar")
public Object updateAvatar(@PathVariable Object organization) {
return null; // TODO implement updateAvatar request controller
@PreAuthorize("@authenticationService.authOrgRequest(T(io.papermc.hangar.model.Permission).EditOrganizationSettings, #organization, true)")
public ModelAndView updateAvatar(@PathVariable String organization) {
try {
URI uri = authenticationService.changeAvatarUri(userService.getCurrentUser().getName(), organization);
return new ModelAndView("redirect:" + uri.toString());
} catch (JsonProcessingException e) {
ModelAndView mav = new ModelAndView("redirect:" + routeHelper.getRouteUrl("users.showProjects", organization));
AlertUtil.showAlert(mav, AlertType.ERROR, "organization.avatarFailed");
return mav;
}
}
@Secured("ROLE_USER")

View File

@ -1,5 +1,8 @@
package io.papermc.hangar.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.papermc.hangar.config.hangar.HangarConfig;
import io.papermc.hangar.controller.util.ApiScope;
import io.papermc.hangar.db.dao.ApiKeyDao;
@ -16,19 +19,28 @@ import io.papermc.hangar.model.Role;
import io.papermc.hangar.model.generated.ApiSessionResponse;
import io.papermc.hangar.model.generated.SessionType;
import io.papermc.hangar.security.HangarAuthentication;
import io.papermc.hangar.service.sso.ChangeAvatarToken;
import io.papermc.hangar.util.AuthUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.annotation.RequestScope;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.util.UriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import java.net.URI;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.UUID;
@ -48,12 +60,14 @@ public class AuthenticationService {
private final PermissionService permissionService;
private final OrgService orgService;
private final UserService userService;
private final RestTemplate restTemplate;
private final ObjectMapper objectMapper;
private static final String UUID_REGEX = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}";
private static final Pattern API_KEY_PATTERN = Pattern.compile("(" + UUID_REGEX + ").(" + UUID_REGEX + ")");
@Autowired
public AuthenticationService(HttpServletRequest request, ApiAuthInfo apiAuthInfo, HangarConfig hangarConfig, HangarDao<UserDao> userDao, HangarDao<SessionsDao> sessionsDao, HangarDao<ApiKeyDao> apiKeyDao, AuthenticationManager authenticationManager, RoleService roleService, PermissionService permissionService, OrgService orgService, UserService userService) {
public AuthenticationService(HttpServletRequest request, ApiAuthInfo apiAuthInfo, HangarConfig hangarConfig, HangarDao<UserDao> userDao, HangarDao<SessionsDao> sessionsDao, HangarDao<ApiKeyDao> apiKeyDao, AuthenticationManager authenticationManager, RoleService roleService, PermissionService permissionService, OrgService orgService, UserService userService, RestTemplate restTemplate, ObjectMapper objectMapper) {
this.request = request;
this.apiAuthInfo = apiAuthInfo;
this.hangarConfig = hangarConfig;
@ -65,6 +79,8 @@ public class AuthenticationService {
this.permissionService = permissionService;
this.orgService = orgService;
this.userService = userService;
this.restTemplate = restTemplate;
this.objectMapper = objectMapper;
}
public ApiAuthInfo getApiAuthInfo(String token) {
@ -219,4 +235,22 @@ public class AuthenticationService {
SecurityContextHolder.getContext().setAuthentication(auth);
}
public URI changeAvatarUri(String requester, String organization) throws JsonProcessingException {
ChangeAvatarToken token = getChangeAvatarToken(requester, organization);
UriComponentsBuilder uriComponents = UriComponentsBuilder.fromHttpUrl(hangarConfig.getAuthUrl());
uriComponents.path("/accounts/user/{organization}/change-avatar/").queryParam("key", token.getSignedData());
return uriComponents.build(organization);
}
public ChangeAvatarToken getChangeAvatarToken(String requester, String organization) throws JsonProcessingException {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> bodyMap = new LinkedMultiValueMap<>();
bodyMap.add("api-key", hangarConfig.sso.getApiKey());
bodyMap.add("request_username", requester);
ChangeAvatarToken token;
token = objectMapper.treeToValue(restTemplate.postForObject(hangarConfig.security.api.getUrl() + "/api/users/" + organization + "/change-avatar-token/", new HttpEntity<>(bodyMap, headers), ObjectNode.class), ChangeAvatarToken.class);
return token;
}
}

View File

@ -0,0 +1,48 @@
package io.papermc.hangar.service.sso;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class ChangeAvatarToken {
private final String signedData;
private final String targetUsername;
private final int requestUserId;
public ChangeAvatarToken(String signedData, String targetUsername, int requestUserId) {
this.signedData = signedData;
this.targetUsername = targetUsername;
this.requestUserId = requestUserId;
}
public String getSignedData() {
return signedData;
}
public String getTargetUsername() {
return targetUsername;
}
public int getRequestUserId() {
return requestUserId;
}
@JsonCreator
public static ChangeAvatarToken of(ObjectNode objectNode) {
ObjectNode rawData = (ObjectNode) objectNode.get("raw_data");
return new ChangeAvatarToken(
objectNode.get("signed_data").asText(),
rawData.get("target_username").asText(),
rawData.get("request_user_id").asInt()
);
}
@Override
public String toString() {
return "ChangeAvatarToken{" +
"signedData='" + signedData + '\'' +
", targetUsername='" + targetUsername + '\'' +
", requestUserId=" + requestUserId +
'}';
}
}