Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.netgrif.application.engine.integration.modules.ModuleHolder
import com.netgrif.application.engine.mail.domain.MailDraft
import com.netgrif.application.engine.mail.interfaces.IMailAttemptService
import com.netgrif.application.engine.mail.interfaces.IMailService
import com.netgrif.application.engine.objects.annotations.Authorize
import com.netgrif.application.engine.objects.auth.domain.AbstractUser
import com.netgrif.application.engine.objects.auth.domain.ActorTransformer
import com.netgrif.application.engine.menu.services.interfaces.DashboardItemService
Expand Down Expand Up @@ -1414,10 +1415,16 @@ class ActionDelegate extends DelegateExpando {
changeUserByEmail(email, "email", cl)
},
name : { cl ->
changeUserByEmail(email, "name", cl)
changeUserByEmail(email, "firstName", cl)
},
firstName : { cl ->
changeUserByEmail(email, "firstName", cl)
},
surname: { cl ->
changeUserByEmail(email, "surname", cl)
changeUserByEmail(email, "lastName", cl)
},
lastName : { cl ->
changeUserByEmail(email, "lastName", cl)
},
tel : { cl ->
changeUserByEmail(email, "tel", cl)
Expand All @@ -1430,10 +1437,16 @@ class ActionDelegate extends DelegateExpando {
changeUser(id, "email", cl)
},
name : { cl ->
changeUser(id, "name", cl)
changeUser(id, "firstName", cl)
},
firstName : { cl ->
changeUser(id, "firstName", cl)
},
surname: { cl ->
changeUser(id, "surname", cl)
changeUser(id, "lastName", cl)
},
lastName : { cl ->
changeUser(id, "lastName", cl)
},
tel : { cl ->
changeUser(id, "tel", cl)
Expand All @@ -1446,10 +1459,16 @@ class ActionDelegate extends DelegateExpando {
changeUser(user, "email", cl)
},
name : { cl ->
changeUser(user, "name", cl)
changeUser(user, "firstName", cl)
},
firstName : { cl ->
changeUser(user, "firstName", cl)
},
surname: { cl ->
changeUser(user, "surname", cl)
changeUser(user, "lastName", cl)
},
lastName : { cl ->
changeUser(user, "lastName", cl)
},
tel : { cl ->
changeUser(user, "tel", cl)
Expand All @@ -1458,7 +1477,7 @@ class ActionDelegate extends DelegateExpando {
}

def changeUserByEmail(String email, String attribute, def cl) {
Optional<AbstractUser> userOptional = userService.findUserByUsername(email, null)
Optional<AbstractUser> userOptional = userService.findUserByEmail(email, null)
if (!userOptional.isPresent()) {
log.error("Cannot find user with email [" + email + "]")
return
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package com.netgrif.application.engine.auth.web;

import com.netgrif.application.engine.adapter.spring.common.web.responsebodies.ResponseMessage;
import com.netgrif.application.engine.auth.service.AuthorityService;
import com.netgrif.application.engine.auth.web.requestbodies.NewAuthorityRequest;
import com.netgrif.application.engine.auth.web.responsebodies.AuthorityDto;
import com.netgrif.application.engine.objects.annotations.Authorize;
import com.netgrif.application.engine.objects.auth.domain.Authority;
import com.netgrif.application.engine.workflow.web.responsebodies.MessageResource;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@Slf4j
@RestController
@RequestMapping("/api/authority")
@RequiredArgsConstructor
@ConditionalOnProperty(
value = "nae.user.web.enabled",
havingValue = "true",
matchIfMissing = true
)
@Tag(name = "Authority")
public class AuthorityController {

private final AuthorityService authorityService;

@Authorize(authority = "ADMIN")
@Authorize(authority = "AUTHORITY_DELETE")
@Operation(description = "Delete authority", security = {@SecurityRequirement(name = "BasicAuth")})
@DeleteMapping(value = "/delete/{name}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaTypes.HAL_JSON_VALUE)
public MessageResource delete(@PathVariable String name, Authentication auth) {
try {
authorityService.delete(name);
log.info("Authority [{}] has been deleted successfully.", name);
return new MessageResource(ResponseMessage.createSuccessMessage("Authority [" + name + "] has been deleted successfully."));
} catch (IllegalArgumentException | ResourceNotFoundException e) {
log.error("Failed to delete authority [{}].", name, e);
return new MessageResource(ResponseMessage.createErrorMessage("Failed to delete authority."));
}
}

@Authorize(authority = "ADMIN")
@Authorize(authority = "AUTHORITY_CREATE")
@Operation(description = "Create authority", security = {@SecurityRequirement(name = "BasicAuth")})
@PostMapping(value = "/create", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaTypes.HAL_JSON_VALUE)
public ResponseEntity<AuthorityDto> create(@RequestBody NewAuthorityRequest request) {
try {
Authority authority = authorityService.getOrCreate(request.name);
log.info("Authority [{}] has been created successfully.", authority);
return ResponseEntity.ok(new AuthorityDto(authority));
} catch (IllegalArgumentException | ResourceNotFoundException e) {
log.error("Failed to create authority [{}].", request.name, e);
return null;
}
}

@Operation(description = "Delete authority", security = {@SecurityRequirement(name = "BasicAuth")})
@GetMapping(value = "/all", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaTypes.HAL_JSON_VALUE)
public ResponseEntity<Page<AuthorityDto>> getAll(Pageable pageable) {
Page<Authority> authorities = authorityService.findAll(pageable);
List<AuthorityDto> authorityDtoList = authorities.stream().map(AuthorityDto::new).toList();
return ResponseEntity.ok(new PageImpl<>(authorityDtoList, pageable, authorities.getTotalElements()));
}

@Operation(description = "Delete authority", security = {@SecurityRequirement(name = "BasicAuth")})
@GetMapping(value = "/{name}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaTypes.HAL_JSON_VALUE)
public ResponseEntity<AuthorityDto> getOne(@PathVariable("name") String name) {
Optional<Authority> authority = authorityService.findOptionalByName(name);
if (authority.isPresent()) {
return ResponseEntity.ok(new AuthorityDto(authority.get()));
} else {
log.error("Cannot find authority with name [{}].", name);
return null;
}
}

@Operation(description = "Delete authority", security = {@SecurityRequirement(name = "BasicAuth")})
@GetMapping(value = "/scope/{scope}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaTypes.HAL_JSON_VALUE)
public ResponseEntity<List<AuthorityDto>> getAllByScope(@PathVariable("scope") String scope, Authentication auth) {
List<Authority> authorities = authorityService.findByScope(scope);
List<AuthorityDto> authorityDtoList = authorities.stream().map(AuthorityDto::new).toList();
return ResponseEntity.ok(authorityDtoList);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.netgrif.application.engine.auth.web.requestbodies.UserSearchRequestBody;
import com.netgrif.application.engine.auth.web.responsebodies.PreferencesResource;
import com.netgrif.application.engine.auth.web.responsebodies.User;
import com.netgrif.application.engine.objects.annotations.Authorize;
import com.netgrif.application.engine.objects.auth.domain.AbstractUser;
import com.netgrif.application.engine.objects.auth.domain.Authority;
import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
Expand Down Expand Up @@ -54,7 +55,8 @@ public class UserController {
private final RealmService realmService;
private final UserFactory userFactory;

@PreAuthorize("@authorizationService.hasAuthority('ADMIN')")
@Authorize(authority = "ADMIN")
@Authorize(authority = "USER_CREATE")
@Operation(summary = "Create a new user", description = "Creates a new user in the realm specified by id.")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "User successfully created"),
Expand Down Expand Up @@ -172,44 +174,8 @@ public ResponseEntity<User> getUser(@PathVariable("realmId") String realmId, @Pa
return ResponseEntity.ok(userFactory.getUser(user, locale));
}

// todo step 2, only used in test on frontend
// @Operation(summary = "Update user", security = {@SecurityRequirement(name = "X-Auth-Token")})
// @PostMapping(value = "/update", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
// public ResponseEntity<User> updateUser(@RequestBody UpdateUserRequest updates, Authentication auth, Locale locale) {

/// / todo should this be kept? not relevant anymore?
// if (!serverAuthProperties.isEnableProfileEdit()) {
// return null;
// }
// LoggedUser loggedUser = (LoggedUser) auth.getPrincipal();
// String actorId = updates.getStringId();
// IUser user;
// try {
// user = userService.findById(actorId, updatedUser.getRealmId());
// } catch (IllegalArgumentException e) {
// log.error("Could not find user with id [{}]", actorId, e);
// return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
// }
// user = userService.update(user, updates.getUpdatedUser());
// securityContextService.saveToken(actorId);
// if (Objects.equals(loggedUser.getId(), actorId)) {
// loggedUser.setFirstName(user.getFirstName());
// loggedUser.setLastName(user.getLastName());
// securityContextService.reloadSecurityContext(loggedUser);
// }
// log.info("Updating user " + user.getEmail() + " with data " + updatedUser);
// return ResponseEntity.ok(User.createUser(user));
// }

// todo not used on front, is it needed?
// @Operation(summary = "Get all users with specified roles", security = {@SecurityRequirement(name = "X-Auth-Token")})
// @PostMapping(value = "/role", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
// public ResponseEntity<Page<IUser>> getAllWithRole(@RequestBody Set<String> roleIds, Pageable pageable, Locale locale) {
// Set<ProcessResourceId> roleResourceIds = roleIds == null ? null : roleIds.stream().map(ProcessResourceId::new).collect(Collectors.toSet());
// Page<IUser> page = userService.findAllActiveByProcessRoles(roleResourceIds, pageable);
// return ResponseEntity.ok();
// }
@PreAuthorize("@authorizationService.hasAuthority('ADMIN')")
@Authorize(authority = "ADMIN")
@Authorize(authority = "ROLE_ASSIGN_TO_USER")
@Operation(summary = "Assign roles to the user", description = "Caller must have the ADMIN role", security = {@SecurityRequirement(name = "X-Auth-Token")})
@PutMapping(value = "/{realmId}/{id}/roles", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ApiResponses(value = {
Expand All @@ -231,29 +197,6 @@ public ResponseEntity<ResponseMessage> assignRolesToUser(@PathVariable("realmId"
}
}

//
// @PreAuthorize("@authorizationService.hasAuthority('ADMIN')")
// @Operation(summary = "Assign negative roles to the user", description = "Caller must have the ADMIN role", security = {@SecurityRequirement(name = "X-Auth-Token")})
// @PutMapping(value = "/{realmId}/{id}/negativeRole", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
// @ApiResponses(value = {
// @ApiResponse(responseCode = "200", description = "Selected negative roles assigned successfully"),
// @ApiResponse(responseCode = "400", description = "Requested roles or user with defined id does not exist"),
// @ApiResponse(responseCode = "403", description = "Caller doesn't fulfill the authorisation requirements"),
// @ApiResponse(responseCode = "500", description = "Internal server error")
// })
// public ResponseEntity<ResponseMessage> assignNegativeRolesToUser(@PathVariable("realmId") String realmId, @PathVariable("id") String actorId, @RequestBody Set<String> roleIds, Authentication auth) {
// try {
// AbstractUser user = userService.findById(actorId, realmId);
// processRoleService.assignNegativeRolesToUser(user, roleIds.stream().map(ProcessResourceId::new).collect(Collectors.toSet()), (LoggedUser) auth.getPrincipal());
// log.info("Negative process roles {} assigned to user [{}]", roleIds, actorId);
// return ResponseEntity.ok(ResponseMessage.createSuccessMessage("Selected negative roles assigned to user " + actorId));
// } catch (IllegalArgumentException e) {
// log.error("Assigning negative roles to user with id [{}] has failed!", actorId, e);
// return ResponseEntity.badRequest().body(ResponseMessage.createErrorMessage("Assigning negative roles to user " + actorId + " has failed!"));
// }
// }
//
@PreAuthorize("@authorizationService.hasAuthority('ADMIN')")
@Operation(summary = "Get all authorities of the system",
description = "Caller must have the ADMIN role",
security = {@SecurityRequirement(name = "X-Auth-Token")})
Expand All @@ -267,7 +210,8 @@ public ResponseEntity<List<Authority>> getAllAuthorities() {
return ResponseEntity.ok(authorityService.findAll(Pageable.unpaged()).stream().toList());
}

@PreAuthorize("@authorizationService.hasAuthority('ADMIN')")
@Authorize(authority = "ADMIN")
@Authorize(authority = "AUTHORITY_ASSIGN_TO_USER")
@Operation(summary = "Assign authority to the user",
description = "Caller must have the ADMIN role",
security = {@SecurityRequirement(name = "X-Auth-Token")})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,21 @@ public class CacheConfigurationProperties {
*/
private String loadedModules = "loadedModules";

/**
* Default cache name for caching default user authorities.
*/
private String defaultUserAuthoritiesCache = "defaultUserAuthoritiesCache";

/**
* Default cache name for caching default anonymous authorities.
*/
private String defaultAnonymousAuthoritiesCache = "defaultAnonymousAuthoritiesCache";

/**
* Default cache name for caching default admin authorities.
*/
private String defaultAdminAuthoritiesCache = "defaultAdminAuthoritiesCache";

/**
* A list of additional custom cache names.
* Allows users to define their own cache names for specific use cases.
Expand Down Expand Up @@ -87,7 +102,7 @@ public class CacheConfigurationProperties {
*/
public Set<String> getAllCaches() {
Set<String> caches = new LinkedHashSet<>(Arrays.asList(petriNetById, petriNetByIdentifier, petriNetDefault,
petriNetLatest, petriNetCache, loadedModules));
petriNetLatest, petriNetCache, loadedModules, defaultUserAuthoritiesCache, defaultAnonymousAuthoritiesCache, defaultAdminAuthoritiesCache));
caches.addAll(additional);
return caches;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.netgrif.application.engine.configuration.properties.DataConfigurationProperties;
import com.netgrif.application.engine.elastic.service.interfaces.IElasticIndexService;
import com.netgrif.application.engine.elastic.web.requestbodies.IndexParams;
import com.netgrif.application.engine.objects.annotations.Authorize;
import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
import com.netgrif.application.engine.elastic.service.ReindexingTask;
import com.netgrif.application.engine.workflow.service.CaseSearchService;
Expand Down Expand Up @@ -79,7 +80,8 @@ public void setIndexService(IElasticIndexService indexService) {
this.indexService = indexService;
}

@PreAuthorize("@authorizationService.hasAuthority('ADMIN')")
@Authorize(authority = "ADMIN")
@Authorize(authority = "ELASTIC_REINDEX")
@Operation(summary = "Reindex specified cases",
description = "Caller must have the ADMIN role",
security = {@SecurityRequirement(name = "BasicAuth")})
Expand Down Expand Up @@ -117,7 +119,8 @@ public MessageResource reindex(@RequestBody Map<String, Object> searchBody, Auth
}
}

@PreAuthorize("@authorizationService.hasAuthority('ADMIN')")
@Authorize(authority = "ADMIN")
@Authorize(authority = "ELASTIC_REINDEX")
@Operation(summary = "Reindex all or stale cases with bulk index",
description = "Reindex all or stale cases (specified by IndexParams.indexAll param) with bulk index. Caller must have the ADMIN role",
security = {@SecurityRequirement(name = "BasicAuth")})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.netgrif.application.engine.manager.web;

import com.netgrif.application.engine.objects.annotations.Authorize;
import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
import com.netgrif.application.engine.manager.service.interfaces.ISessionManagerService;
import com.netgrif.application.engine.manager.web.body.request.LogoutRequest;
Expand Down Expand Up @@ -33,7 +34,7 @@ public class SessionManagerController {
@Autowired
private ISessionManagerService sessionManagerService;

@PreAuthorize("hasRole('ADMIN')")
@Authorize(authority = "ADMIN")
@Operation(summary = "Get All logged users",
description = "Caller must have the ADMIN role",
security = {@SecurityRequirement(name = "BasicAuth")})
Expand All @@ -47,7 +48,7 @@ public AllLoggedUsersResponse getAllSessions() {
return new AllLoggedUsersResponse(loggedUsers);
}

@PreAuthorize("hasRole('ADMIN')")
@Authorize(authority = "ADMIN")
@Operation(summary = "Logout current user",
description = "Caller must have the ADMIN role",
security = {@SecurityRequirement(name = "BasicAuth")})
Expand All @@ -62,7 +63,7 @@ public MessageLogoutResponse logoutCurrentSession(@RequestBody LogoutRequest req
return new MessageLogoutResponse(true);
}

@PreAuthorize("hasRole('ADMIN')")
@Authorize(authority = "ADMIN")
@Operation(summary = "Logout all user",
description = "Caller must have the ADMIN role",
security = {@SecurityRequirement(name = "BasicAuth")})
Expand Down
Loading
Loading