Skip to content

Commit 6f49b4c

Browse files
committed
vailidate tty action
1 parent 2cc9460 commit 6f49b4c

File tree

5 files changed

+104
-8
lines changed

5 files changed

+104
-8
lines changed

core/src/main/java/com/flowci/core/auth/WebAuth.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,24 @@
2020
import com.flowci.core.auth.annotation.Action;
2121
import com.flowci.core.auth.service.AuthService;
2222
import com.flowci.core.common.manager.SessionManager;
23+
import com.flowci.core.user.domain.User;
2324
import com.flowci.exception.AccessException;
2425
import com.flowci.exception.AuthenticationException;
26+
import com.flowci.util.StringHelper;
2527
import com.google.common.base.Strings;
2628
import org.springframework.beans.factory.annotation.Autowired;
29+
import org.springframework.messaging.MessageHeaders;
30+
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
2731
import org.springframework.stereotype.Component;
32+
import org.springframework.util.MultiValueMap;
2833
import org.springframework.web.method.HandlerMethod;
2934
import org.springframework.web.servlet.HandlerInterceptor;
3035
import org.springframework.web.servlet.ModelAndView;
3136

3237
import javax.servlet.http.HttpServletRequest;
3338
import javax.servlet.http.HttpServletResponse;
3439
import java.util.Objects;
40+
import java.util.Optional;
3541

3642
/**
3743
* @author yang
@@ -51,6 +57,31 @@ public class WebAuth implements HandlerInterceptor {
5157
@Autowired
5258
private SessionManager sessionManager;
5359

60+
/**
61+
* Get user object from ws message header
62+
* @param headers
63+
* @return User object
64+
* @exception AuthenticationException if Token header is missing or invalid token
65+
*/
66+
public User validate(MessageHeaders headers) {
67+
MultiValueMap<String, String> map = headers.get(StompHeaderAccessor.NATIVE_HEADERS, MultiValueMap.class);
68+
if (Objects.isNull(map)) {
69+
throw new AuthenticationException("Invalid token");
70+
}
71+
72+
String token = map.getFirst(HeaderToken);
73+
if (!StringHelper.hasValue(token)) {
74+
throw new AuthenticationException("Invalid token");
75+
}
76+
77+
Optional<User> user = authService.get(token);
78+
if (!user.isPresent()) {
79+
throw new AuthenticationException("Invalid token");
80+
}
81+
82+
return user.get();
83+
}
84+
5485
@Override
5586
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
5687
if (!authService.isEnabled()) {

core/src/main/java/com/flowci/core/auth/service/AuthService.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919

2020
import com.flowci.core.auth.annotation.Action;
2121
import com.flowci.core.auth.domain.Tokens;
22+
import com.flowci.core.user.domain.User;
23+
24+
import java.util.Optional;
2225

2326
/**
2427
* 'login' ->
@@ -52,11 +55,16 @@ public interface AuthService {
5255
boolean hasPermission(Action action);
5356

5457
/**
55-
* Set current user by token
58+
* Set current logged in user by token
5659
* @return Current user object or null if not verified
5760
*/
5861
boolean set(String token);
5962

63+
/**
64+
* Get current logged in user
65+
*/
66+
Optional<User> get(String token);
67+
6068
/**
6169
* Set current user from default admin form config properties
6270
*/

core/src/main/java/com/flowci/core/auth/service/AuthServiceImpl.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import com.flowci.exception.AuthenticationException;
3030
import com.flowci.util.HashingHelper;
3131
import java.util.Objects;
32+
import java.util.Optional;
33+
3234
import lombok.extern.log4j.Log4j2;
3335
import org.springframework.beans.factory.annotation.Autowired;
3436
import org.springframework.cache.Cache;
@@ -128,20 +130,29 @@ public Tokens refresh(Tokens tokens) {
128130

129131
@Override
130132
public boolean set(String token) {
133+
Optional<User> optional = get(token);
134+
if (optional.isPresent()) {
135+
sessionManager.set(optional.get());
136+
return true;
137+
}
138+
return false;
139+
}
140+
141+
@Override
142+
public Optional<User> get(String token) {
131143
String email = JwtHelper.decode(token);
132144

133145
User user = onlineUsersCache.get(email, User.class);
134146
if (Objects.isNull(user)) {
135-
return false;
147+
return Optional.empty();
136148
}
137149

138150
boolean verify = JwtHelper.verify(token, user, true);
139151
if (verify) {
140-
sessionManager.set(user);
141-
return true;
152+
return Optional.of(user);
142153
}
143154

144-
return false;
155+
return Optional.empty();
145156
}
146157

147158
@Override

core/src/main/java/com/flowci/core/common/config/WebSocketConfig.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,22 @@
1616

1717
package com.flowci.core.common.config;
1818

19+
import com.flowci.core.common.helper.ThreadHelper;
1920
import org.springframework.context.annotation.Bean;
2021
import org.springframework.context.annotation.Configuration;
22+
import org.springframework.messaging.Message;
23+
import org.springframework.messaging.MessageChannel;
24+
import org.springframework.messaging.converter.MessageConverter;
25+
import org.springframework.messaging.simp.config.ChannelRegistration;
2126
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
27+
import org.springframework.messaging.support.ChannelInterceptor;
28+
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
2229
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
2330
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
2431
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
2532

33+
import java.util.List;
34+
2635
/**
2736
* @author yang
2837
*/
@@ -118,4 +127,16 @@ public void configureMessageBroker(MessageBrokerRegistry registry) {
118127
registry.enableSimpleBroker("/topic");
119128
registry.setApplicationDestinationPrefixes("/app");
120129
}
130+
131+
@Override
132+
public void configureClientInboundChannel(ChannelRegistration registration) {
133+
ThreadPoolTaskExecutor executor = ThreadHelper.createTaskExecutor(50, 50, 50, "ws-inbound-");
134+
registration.taskExecutor(executor);
135+
}
136+
137+
@Override
138+
public void configureClientOutboundChannel(ChannelRegistration registration) {
139+
ThreadPoolTaskExecutor executor = ThreadHelper.createTaskExecutor(50, 50, 50, "ws-outbound-");
140+
registration.taskExecutor(executor);
141+
}
121142
}
Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,57 @@
11
package com.flowci.core.job.controller;
22

3+
import com.flowci.core.auth.WebAuth;
34
import com.flowci.core.job.service.TtyService;
5+
import com.flowci.core.user.domain.User;
6+
import com.flowci.exception.AuthenticationException;
47
import lombok.extern.log4j.Log4j2;
58
import org.springframework.beans.factory.annotation.Autowired;
9+
import org.springframework.messaging.MessageHeaders;
610
import org.springframework.messaging.handler.annotation.DestinationVariable;
11+
import org.springframework.messaging.handler.annotation.MessageExceptionHandler;
712
import org.springframework.messaging.handler.annotation.MessageMapping;
813
import org.springframework.messaging.handler.annotation.Payload;
14+
import org.springframework.messaging.simp.annotation.SendToUser;
915
import org.springframework.stereotype.Controller;
1016

1117
@Log4j2
1218
@Controller
1319
public class TtyController {
1420

21+
@Autowired
22+
private WebAuth webAuth;
23+
1524
@Autowired
1625
private TtyService ttyService;
1726

27+
@MessageExceptionHandler(AuthenticationException.class)
28+
@SendToUser("/topic/tty/errors")
29+
public Exception handleExceptions(AuthenticationException e) {
30+
return e;
31+
}
32+
1833
@MessageMapping("/tty/{jobId}/open")
19-
public void open(@DestinationVariable String jobId) {
34+
public void open(@DestinationVariable String jobId, MessageHeaders headers) {
35+
validate(headers);
2036
ttyService.open(jobId);
2137
}
2238

2339
@MessageMapping("/tty/{jobId}/shell")
24-
public void shell(@DestinationVariable String jobId, @Payload String script) {
40+
public void shell(@DestinationVariable String jobId, @Payload String script, MessageHeaders headers) {
41+
validate(headers);
2542
ttyService.shell(jobId, script);
2643
}
2744

2845
@MessageMapping("/tty/{jobId}/close")
29-
public void close(@DestinationVariable String jobId) {
46+
public void close(@DestinationVariable String jobId, MessageHeaders headers) {
47+
validate(headers);
3048
ttyService.close(jobId);
3149
}
50+
51+
private void validate(MessageHeaders headers) {
52+
User user = webAuth.validate(headers);
53+
if (!user.isAdmin()) {
54+
throw new AuthenticationException("Admin permission is required");
55+
}
56+
}
3257
}

0 commit comments

Comments
 (0)