Skip to content
Merged
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 @@ -13,6 +13,7 @@
import java.util.Map;
import javax.crypto.SecretKey;

import org.openmbee.mms.core.services.TokenService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
Expand All @@ -22,7 +23,7 @@
import org.springframework.stereotype.Component;

@Component
public class JwtTokenGenerator implements Serializable {
public class JwtTokenGenerator implements Serializable, TokenService {

private static final long serialVersionUID = 6463567580980594813L;
private static final String CLAIM_KEY_USERNAME = "sub";
Expand Down Expand Up @@ -103,15 +104,26 @@ private boolean isTokenExpired(String token) {
return expirationDate.before(new Date());
}

@Override
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();

List<String> authorities = new ArrayList<>();
for (GrantedAuthority ga : userDetails.getAuthorities()) {
authorities.add(ga.getAuthority());
}
claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
claims.put(CLAIM_KEY_USERID, userDetails.getUsername());
claims.put(CLAIM_KEY_ENABLED, userDetails.isEnabled());
return generateToken(userDetails.getUsername(), userDetails.isEnabled(), authorities);
}

@Override
public String generateToken(String principal, Collection<String> authorities) {
return generateToken(principal, true, authorities);
}

private String generateToken(String principal, boolean enabled, Collection<String> authorities) {
Map<String, Object> claims = new HashMap<>();
claims.put(CLAIM_KEY_USERNAME, principal);
claims.put(CLAIM_KEY_USERID, principal);
claims.put(CLAIM_KEY_ENABLED, enabled);
claims.put(CLAIM_KEY_CREATED, new Date());
claims.put(CLAIM_KEY_AUTHORITIES, authorities);
return generateToken(claims);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.openmbee.mms.core.config;

import java.util.*;
import java.util.regex.Pattern;

public class Constants {

Expand All @@ -17,6 +18,8 @@ public class Constants {

public static final String MASTER_BRANCH = "master";

public static final Pattern BRANCH_ID_VALID_PATTERN = Pattern.compile("^[\\w-]+$");

public static final Map<String, List> RPmap = new LinkedHashMap<>();
public static final List<String> aPriv;
public static final List<String> rPriv;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.openmbee.mms.core.objects;

import io.swagger.v3.oas.annotations.media.Schema;

public class ElementsCommitResponse extends ElementsResponse {

@Schema(nullable = true)
private String commitId;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add @Schema(nullable = true) for openapi

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added


public String getCommitId() {
return commitId;
}

public void setCommitId(String commitId) {
this.commitId = commitId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.io.OutputStream;
import java.util.Map;

import org.openmbee.mms.core.objects.ElementsCommitResponse;
import org.openmbee.mms.core.objects.ElementsRequest;
import org.openmbee.mms.core.objects.ElementsResponse;
import org.openmbee.mms.data.domains.scoped.Node;
Expand All @@ -17,16 +18,16 @@ public interface NodeService {

ElementsResponse read(String projectId, String refId, ElementsRequest req, Map<String, String> params);

ElementsResponse createOrUpdate(String projectId, String refId, ElementsRequest req,
Map<String, String> params, String user);
ElementsCommitResponse createOrUpdate(String projectId, String refId, ElementsRequest req,
Map<String, String> params, String user);

void extraProcessPostedElement(ElementJson element, Node node, NodeChangeInfo info);

void extraProcessDeletedElement(ElementJson element, Node node, NodeChangeInfo info);

void extraProcessGotElement(ElementJson element, Node node, NodeGetInfo info);

ElementsResponse delete(String projectId, String refId, String id, String user);
ElementsCommitResponse delete(String projectId, String refId, String id, String user);

ElementsResponse delete(String projectId, String refId, ElementsRequest req, String user);
ElementsCommitResponse delete(String projectId, String refId, ElementsRequest req, String user);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.openmbee.mms.core.services;

import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

public interface TokenService {
String generateToken(UserDetails userDetails);
String generateToken(String principal, Collection<String> authorities);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
import java.util.ArrayList;
import java.util.List;

import static org.openmbee.mms.core.config.Constants.BRANCH_ID_VALID_PATTERN;

@RestController
@RequestMapping("/projects/{projectId}/refs")
@Tag(name = "Refs")
public class BranchesController extends BaseController {

private static final String BRANCH_ID_VALID_PATTERN = "^[\\w-]+$";

private BranchService branchService;

@Autowired
Expand Down Expand Up @@ -118,6 +118,6 @@ public RefsResponse deleteRef(
}

static boolean isBranchIdValid(String branchId) {
return branchId != null && branchId.matches(BRANCH_ID_VALID_PATTERN);
return branchId != null && BRANCH_ID_VALID_PATTERN.matcher(branchId).matches();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.io.InputStream;
import java.util.*;

import org.openmbee.mms.core.objects.ElementsCommitResponse;
import org.openmbee.mms.core.objects.ElementsRequest;
import org.openmbee.mms.core.objects.ElementsResponse;
import org.openmbee.mms.core.services.CommitService;
Expand Down Expand Up @@ -107,7 +108,7 @@ public ElementsResponse getElement(

@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("@mss.hasBranchPrivilege(authentication, #projectId, #refId, 'BRANCH_EDIT_CONTENT', false)")
public ElementsResponse createOrUpdateElements(
public ElementsCommitResponse createOrUpdateElements(
@PathVariable String projectId,
@PathVariable String refId,
@RequestBody ElementsRequest req,
Expand Down Expand Up @@ -194,13 +195,13 @@ public ElementsResponse getElements(

@DeleteMapping(value = "/{elementId}")
@PreAuthorize("@mss.hasBranchPrivilege(authentication, #projectId, #refId, 'BRANCH_EDIT_CONTENT', false)")
public ElementsResponse deleteElement(
public ElementsCommitResponse deleteElement(
@PathVariable String projectId,
@PathVariable String refId,
@PathVariable String elementId,
Authentication auth) {

ElementsResponse res = getNodeService(projectId).delete(projectId, refId, elementId, auth.getName());
ElementsCommitResponse res = getNodeService(projectId).delete(projectId, refId, elementId, auth.getName());
handleSingleResponse(res);
return res;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.openmbee.mms.core.exceptions.BadRequestException;
import org.openmbee.mms.core.objects.ElementsCommitResponse;
import org.openmbee.mms.core.objects.EventObject;
import org.openmbee.mms.core.services.EventService;
import org.openmbee.mms.core.services.NodeChangeInfo;
Expand Down Expand Up @@ -183,8 +184,8 @@ public ElementsResponse read(String projectId, String refId, ElementsRequest req
}

@Override
public ElementsResponse createOrUpdate(String projectId, String refId, ElementsRequest req,
Map<String, String> params, String user) {
public ElementsCommitResponse createOrUpdate(String projectId, String refId, ElementsRequest req,
Map<String, String> params, String user) {

ContextHolder.setContext(projectId, refId);
boolean overwriteJson = Boolean.parseBoolean(params.get("overwrite"));
Expand All @@ -197,9 +198,12 @@ public ElementsResponse createOrUpdate(String projectId, String refId, ElementsR

commitChanges(info);

ElementsResponse response = new ElementsResponse();
ElementsCommitResponse response = new ElementsCommitResponse();
response.getElements().addAll(info.getUpdatedMap().values());
response.setRejected(new ArrayList<>(info.getRejected().values()));
if(!info.getUpdatedMap().isEmpty()) {
response.setCommitId(info.getCommitJson().getId());
}
return response;
}

Expand Down Expand Up @@ -262,7 +266,7 @@ public void extraProcessGotElement(ElementJson element, Node node, NodeGetInfo i
}

@Override
public ElementsResponse delete(String projectId, String refId, String id, String user) {
public ElementsCommitResponse delete(String projectId, String refId, String id, String user) {
ElementsRequest req = buildRequest(id);
return delete(projectId, refId, req, user);
}
Expand All @@ -286,18 +290,21 @@ protected ElementsRequest buildRequest(Collection<String> ids) {
}

@Override
public ElementsResponse delete(String projectId, String refId, ElementsRequest req, String user) {
public ElementsCommitResponse delete(String projectId, String refId, ElementsRequest req, String user) {
ContextHolder.setContext(projectId, refId);

NodeChangeInfo info = nodeDeleteHelper
.processDeleteJson(req.getElements(), createCommit(user, refId, projectId, req, null),
this);
ElementsResponse response = new ElementsResponse();
ElementsCommitResponse response = new ElementsCommitResponse();

commitChanges(info);

response.getElements().addAll(info.getDeletedMap().values());
response.setRejected(new ArrayList<>(info.getRejected().values()));
if(!info.getDeletedMap().isEmpty()) {
response.setCommitId(info.getCommitJson().getId());
}
return response;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public Object updatePassword(@RequestBody UserCreateRequest req,

try {
if (requesterAdmin || requester.equals(req.getUsername())) {
userDetailsService.changeUserPassword(req.getUsername(), req.getPassword());
userDetailsService.changeUserPassword(req.getUsername(), req.getPassword(), requesterAdmin);
} else {
throw new UnauthorizedException("Not authorized");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,26 +51,31 @@ public User register(UserCreateRequest req) {
user.setFirstName(req.getFirstname());
user.setLastName(req.getLastname());
user.setUsername(req.getUsername());
user.setPassword(passwordEncoder.encode(req.getPassword()));
user.setPassword(encodePassword(req.getPassword()));
user.setEnabled(true);
user.setAdmin(req.isAdmin());
return userRepository.save(user);
}

@Transactional
public void changeUserPassword(String username, String password) {
public void changeUserPassword(String username, String password, boolean asAdmin) {
Optional<User> userOptional = userRepository.findByUsername(username);
if(! userOptional.isPresent()) {
throw new UsernameNotFoundException(
String.format("No user found with username '%s'.", username));
}

User user = userOptional.get();
if(user.getPassword() == null || user.getPassword().isEmpty()) {
if(!asAdmin && (user.getPassword() == null || user.getPassword().isEmpty())) {
throw new ForbiddenException("Cannot change or set passwords for external users.");
}

user.setPassword(passwordEncoder.encode(password));
//TODO password strength test?
user.setPassword(encodePassword(password));
userRepository.save(user);
}

private String encodePassword(String password) {
return (password != null && !password.isEmpty()) ? passwordEncoder.encode(password) : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ public void deleteProjectDatabase(Project project) throws SQLException {
+ databaseProjectString(project) + "';"));
}
statement.executeUpdate(connection.nativeSQL("DROP DATABASE " + databaseProjectString(project)));

//TODO: if using PG 13, can use the following
//statement.executeUpdate(connection.nativeSQL("DROP DATABASE " + databaseProjectString(project) + " WITH (FORCE)"));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;

import java.util.regex.Pattern;

import static org.openmbee.mms.core.config.Constants.BRANCH_ID_VALID_PATTERN;

public abstract class BaseDAOImpl {

private CrudDataSources crudDataSources;
Expand Down Expand Up @@ -36,6 +40,10 @@ public JdbcTemplate getConn() {

public String getSuffix() {
String refId = ContextHolder.getContext().getBranchId();
return refId.equals(ContextObject.MASTER_BRANCH) ? "" : refId.toLowerCase();
if(BRANCH_ID_VALID_PATTERN.matcher(refId).matches()) {
return refId.equals(ContextObject.MASTER_BRANCH) ? "" : refId.toLowerCase();
} else {
throw new IllegalArgumentException("Bad branch id, aborting current operation.");
}
}
}
24 changes: 23 additions & 1 deletion twc/src/main/java/org/openmbee/mms/twc/config/TwcConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import org.springframework.context.annotation.Configuration;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Configuration
@ConfigurationProperties("twc")
Expand All @@ -18,6 +20,8 @@ public class TwcConfig {

private List<TeamworkCloud> instances;

private boolean useAuthDelegation = false;

public List<TeamworkCloud> getInstances() {
return instances;
}
Expand All @@ -26,6 +30,14 @@ public void setInstances(List<TeamworkCloud> instances) {
this.instances = instances;
}

public boolean isUseAuthDelegation() {
return useAuthDelegation;
}

public void setUseAuthDelegation(boolean useAuthDelegation) {
this.useAuthDelegation = useAuthDelegation;
}

public TwcAuthenticationProvider getAuthNProvider(String associatedTWC) {
if(associatedTWC == null)
return null;
Expand All @@ -39,11 +51,21 @@ public TwcAuthenticationProvider getAuthNProvider(String associatedTWC) {
}

public TeamworkCloud getTeamworkCloud(String twcUrl) {
String host = stripHost(twcUrl);
for(TeamworkCloud twc : getInstances()) {
if (twc.hasKnownName(twcUrl)) {
if (twc.hasKnownName(host)) {
return twc;
}
}
return null;
}

private static String stripHost(String url) {
Pattern pattern = Pattern.compile("(https?://)?([\\w-\\.]*)(:\\d+)?");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should check this and possibly move it to a static final.

Matcher matcher = pattern.matcher(url);
if(matcher.matches()) {
return matcher.group(2);
}
return url;
}
}
Loading