Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/GMOD/Apollo into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
nathandunn committed Apr 7, 2021
2 parents 708a2b7 + 84eee66 commit 1728c28
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 6 deletions.
1 change: 1 addition & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Features

- Added getAttributions method [2591](https://github.com/GMOD/Apollo/pull/2591) via @mbc32.
- Make getting track features by location optional to pull unique code [2600](https://github.com/GMOD/Apollo/pull/2600).
- Added additional websocket authentication support [2598](https://github.com/GMOD/Apollo/pull/2598).

Bug Fix

Expand Down
1 change: 1 addition & 0 deletions grails-app/conf/Config.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ apollo {

grails.plugin.databasemigration.updateOnStart = true
grails.plugin.databasemigration.updateOnStartFileNames = ['changelog.groovy']
grails.plugin.springwebsocket.useCustomConfig = true

// from: http://grails.org/plugin/audit-logging
auditLog {
Expand Down
12 changes: 12 additions & 0 deletions grails-app/conf/spring/resources.groovy
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import com.brandseye.cors.CorsFilter
import grails.plugin.springwebsocket.GrailsSimpAnnotationMethodMessageHandler

// Place your Spring DSL code here
beans = {
corsFilter(CorsFilter)

webSocketConfig org.bbop.apollo.websocket.WebSocketConfig

grailsSimpAnnotationMethodMessageHandler(
GrailsSimpAnnotationMethodMessageHandler,
ref("clientInboundChannel"),
ref("clientOutboundChannel"),
ref("brokerMessagingTemplate")
) {
destinationPrefixes = ["/app"]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.bbop.apollo
import grails.converters.JSON
import groovy.json.JsonBuilder
import org.apache.shiro.SecurityUtils
import org.apache.shiro.session.Session
import org.bbop.apollo.event.AnnotationEvent
import org.bbop.apollo.event.AnnotationListener
import org.bbop.apollo.gwt.shared.FeatureStringEnum
Expand Down Expand Up @@ -1275,8 +1276,8 @@ class AnnotationEditorController extends AbstractApolloController implements Ann
JSONObject rootElement = (JSONObject) JSON.parse(inputString)
rootElement.put(FeatureStringEnum.USERNAME.value, principal.name)


String operation = ((JSONObject) rootElement).get(REST_OPERATION)
log.debug "prinicial name ${principal?.name}"

String operationName = underscoreToCamelCase(operation)
log.debug "operationName: ${operationName}"
Expand All @@ -1285,16 +1286,28 @@ class AnnotationEditorController extends AbstractApolloController implements Ann
case "currentUser":
User user = permissionService.getCurrentUser(rootElement)
return user as JSON
// test case for websocket
// test case
case "ping":
return "pong"
break
// test case
// test case
case "broadcast":
broadcastMessage("pong",principal?.name)
break
// test case
case "logout":
SecurityUtils.subject.logout()
try {
SecurityUtils.subject.logout()
} catch (e) {
log.warn "No thread, so sending through websocket instead ${e}"
}
finally {
if(principal?.name){
JSONObject jsonObject = new JSONObject()
jsonObject.put(FeatureStringEnum.USERNAME.value,principal.name)
jsonObject.put(REST_OPERATION,"logout")
brokerMessagingTemplate.convertAndSend "/topic/AnnotationNotification/user/" + principal.name, jsonObject.toString()
}
}
break
case "setToDownstreamDonor": requestHandlingService.setDonor(rootElement, false)
break
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class UsernamePasswordAuthenticatorService implements AuthenticatorService{

}


@Override
Boolean requiresToken() {
return true
Expand Down
38 changes: 38 additions & 0 deletions src/groovy/org/bbop/apollo/websocket/ApolloHandshakeHandler.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.bbop.apollo.websocket


import java.security.Principal

import org.springframework.http.HttpStatus
import org.springframework.http.server.ServerHttpRequest
import org.springframework.http.server.ServerHttpResponse
import org.springframework.web.socket.WebSocketHandler
import org.springframework.web.socket.server.HandshakeHandler
import org.springframework.web.socket.server.HandshakeFailureException
import org.springframework.web.socket.server.support.DefaultHandshakeHandler

class ApolloHandshakeHandler implements HandshakeHandler {

DefaultHandshakeHandler defaultHandshakeHandler = new DefaultHandshakeHandler()
AuthenticatingHandshakeHandler handshakeHandler = new AuthenticatingHandshakeHandler()

final boolean doHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Map<String, Object> attributes
) throws HandshakeFailureException {

Principal user = defaultHandshakeHandler.determineUser(request, wsHandler, attributes)
if (user == null) {
Principal newUser = handshakeHandler.determineUser(request, wsHandler, attributes)
if (newUser == null) {
response.setStatusCode(HttpStatus.FORBIDDEN)
return false
}
return handshakeHandler.doHandshake(request, response, wsHandler, attributes)
}
return defaultHandshakeHandler.doHandshake(request, response, wsHandler, attributes)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.bbop.apollo.websocket


import grails.util.Holders
import org.apache.shiro.SecurityUtils

import javax.security.auth.Subject
import java.security.Principal

import org.apache.shiro.authc.UsernamePasswordToken
import org.bbop.apollo.websocket.StompPrincipal
import org.springframework.http.server.ServerHttpRequest
import org.springframework.web.socket.WebSocketHandler
import org.springframework.web.socket.server.HandshakeHandler
import org.springframework.web.socket.server.support.DefaultHandshakeHandler

class AuthenticatingHandshakeHandler extends DefaultHandshakeHandler {
def usernamePasswordAuthenticatorService = Holders.grailsApplication.mainContext.getBean('usernamePasswordAuthenticatorService')

@Override
Principal determineUser(
ServerHttpRequest request,
WebSocketHandler wsHandler,
Map<String, Object> attributes
) {
// https://stackoverflow.com/a/41584987/10750707
def query = request.getURI().getQuery()
def queryParams = query.split('&')
def mapParams = queryParams.collectEntries { param -> param.split('=').collect { URLDecoder.decode(it) }}
String username = mapParams["username"]
String password = mapParams["password"]
if (!(username && password)) {
return null
}
UsernamePasswordToken authToken = new UsernamePasswordToken(username, password)
if(usernamePasswordAuthenticatorService.authenticate(authToken,null)){
return request.getPrincipal()
}
return null
}

}
17 changes: 17 additions & 0 deletions src/groovy/org/bbop/apollo/websocket/StompPrincipal.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.bbop.apollo.websocket


import java.security.Principal

class StompPrincipal implements Principal {
String userName

StompPrincipal(userName) {
this.userName = userName
}

@Override
public String getName() {
return this.userName
}
}
23 changes: 23 additions & 0 deletions src/groovy/org/bbop/apollo/websocket/WebSocketConfig.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.bbop.apollo.websocket

import org.springframework.context.annotation.Configuration
import org.springframework.messaging.simp.config.MessageBrokerRegistry
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker
import org.springframework.web.socket.config.annotation.StompEndpointRegistry

@Configuration
@EnableWebSocketMessageBroker
class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

private final def apolloHandshakeHandler = new ApolloHandshakeHandler()

@Override
void registerStompEndpoints(StompEndpointRegistry ser) {
ser.addEndpoint("/stomp")
.setAllowedOrigins("*")
.setHandshakeHandler(apolloHandshakeHandler)
.withSockJS()
}

}

0 comments on commit 1728c28

Please sign in to comment.