java - Failed to create WebSocket connection when Spring Security is on -
im using java websocket client subscribe spring-boot based server application. worked fine, after adding support spring security in order authenticate , authorize users, websocket java client stopped working. im getting following errors (post request failed 405 not allowed error)
19:56:49.813 [main] info o.s.s.c.threadpooltaskscheduler - initializing executorservice 19:56:49.819 [main] debug stompwebsockettestclient - connecting , subscribing 1 users 19:56:49.886 [main] debug o.s.w.s.s.c.resttemplatexhrtransport - executing sockjs info request, url=http:<//>localhost:9090/hello/info 19:56:49.923 [main] debug o.s.web.client.resttemplate - created request "http:<//>localhost:9090/hello/info" 19:56:49.941 [main] debug o.s.web.client.resttemplate - request "http:<//>localhost:9090/hello/info" resulted in 200 (ok) 19:56:49.974 [main] debug o.s.w.s.s.client.websockettransport - starting websocket session url=ws:<//>localhost:9090/hello/912/d93d47eb2bdd4700a26c0e19e10a33df/websocket 19:56:49.974 [main] debug o.s.w.s.c.s.standardwebsocketclient - connecting ws:<//>localhost:9090/hello/912/d93d47eb2bdd4700a26c0e19e10a33df/websocket 19:56:50.120 [simpleasynctaskexecutor-1] error o.s.w.s.s.c.defaulttransportrequest - transportrequest[url=ws:<//>localhost:9090/hello/912/d93d47eb2bdd4700a26c0e19e10a33df/websocket] failed. falling on next transport. javax.websocket.deploymentexception: http response server [http/1.1 200 ok ] did not permit http upgrade websocket @ org.apache.tomcat.websocket.wswebsocketcontainer.parsestatus(wswebsocketcontainer.java:619) ~[tomcat-embed-websocket-8.0.15.jar:8.0.15] @ org.apache.tomcat.websocket.wswebsocketcontainer.processresponse(wswebsocketcontainer.java:603) ~[tomcat-embed-websocket-8.0.15.jar:8.0.15] @ org.apache.tomcat.websocket.wswebsocketcontainer.connecttoserver(wswebsocketcontainer.java:300) ~[tomcat-embed-websocket-8.0.15.jar:8.0.15] @ org.springframework.web.socket.client.standard.standardwebsocketclient$1.call(standardwebsocketclient.java:152) ~[spring-websocket-4.2.0.rc1.jar:4.2.0.rc1] @ org.springframework.web.socket.client.standard.standardwebsocketclient$1.call(standardwebsocketclient.java:149) ~[spring-websocket-4.2.0.rc1.jar:4.2.0.rc1] @ java.util.concurrent.futuretask.run(futuretask.java:266) ~[na:1.8.0_45] @ java.lang.thread.run(thread.java:745) [na:1.8.0_45] 19:56:50.122 [simpleasynctaskexecutor-1] debug o.s.w.s.s.c.resttemplatexhrtransport - starting xhr streamingsession url=http:<//>localhost:9090/hello/912/d93d47eb2bdd4700a26c0e19e10a33df/xhr_streaming 19:56:50.128 [simpleasynctaskexecutor-1] debug o.s.web.client.resttemplate - created post request "http:<//>localhost:9090/hello/912/d93d47eb2bdd4700a26c0e19e10a33df/xhr_streaming" 19:56:50.133 [simpleasynctaskexecutor-1] warn o.s.web.client.resttemplate - post request "http:<//>localhost:9090/hello/912/d93d47eb2bdd4700a26c0e19e10a33df/xhr_streaming" resulted in 405 (method not allowed); invoking error handler 19:56:50.139 [simpleasynctaskexecutor-1] error o.s.w.s.s.c.defaulttransportrequest - transportrequest[url=http:<//>localhost:9090/hello/912/d93d47eb2bdd4700a26c0e19e10a33df/xhr_streaming] failed. falling on next transport. org.springframework.web.client.httpclienterrorexception: 405 method not allowed @ org.springframework.web.client.defaultresponseerrorhandler.handleerror(defaultresponseerrorhandler.java:91) ~[spring-web-4.1.3.release.jar:4.1.3.release] @ org.springframework.web.client.resttemplate.handleresponseerror(resttemplate.java:615) ~[spring-web-4.1.3.release.jar:4.1.3.release] @ org.springframework.web.client.resttemplate.doexecute(resttemplate.java:573) ~[spring-web-4.1.3.release.jar:4.1.3.release] @ org.springframework.web.client.resttemplate.execute(resttemplate.java:544) ~[spring-web-4.1.3.release.jar:4.1.3.release] @ org.springframework.web.socket.sockjs.client.resttemplatexhrtransport$1.run(resttemplatexhrtransport.java:128) ~[spring-websocket-4.2.0.rc1.jar:4.2.0.rc1] @ java.lang.thread.run(thread.java:745) [na:1.8.0_45] 19:56:50.140 [simpleasynctaskexecutor-1] debug o.s.w.s.s.c.resttemplatexhrtransport - starting xhr streamingsession url=http:<//>localhost:9090/hello/912/d93d47eb2bdd4700a26c0e19e10a33df/xhr 19:56:50.155 [simpleasynctaskexecutor-2] debug o.s.web.client.resttemplate - created post request "http:<//>localhost:9090/hello/912/d93d47eb2bdd4700a26c0e19e10a33df/xhr" 19:56:50.163 [simpleasynctaskexecutor-2] warn o.s.web.client.resttemplate - post request "http:<//>localhost:9090/hello/912/d93d47eb2bdd4700a26c0e19e10a33df/xhr" resulted in 405 (method not allowed); invoking error handler 19:56:50.166 [simpleasynctaskexecutor-2] error o.s.w.s.s.c.defaulttransportrequest - no more fallback transports after transportrequest[url=http:<//>localhost:9090/hello/912/d93d47eb2bdd4700a26c0e19e10a33df/xhr] org.springframework.web.client.httpclienterrorexception: 405 method not allowed @ org.springframework.web.client.defaultresponseerrorhandler.handleerror(defaultresponseerrorhandler.java:91) ~[spring-web-4.1.3.release.jar:4.1.3.release] @ org.springframework.web.client.resttemplate.handleresponseerror(resttemplate.java:615) ~[spring-web-4.1.3.release.jar:4.1.3.release] @ org.springframework.web.client.resttemplate.doexecute(resttemplate.java:573) ~[spring-web-4.1.3.release.jar:4.1.3.release] @ org.springframework.web.client.resttemplate.execute(resttemplate.java:544) ~[spring-web-4.1.3.release.jar:4.1.3.release] @ org.springframework.web.socket.sockjs.client.resttemplatexhrtransport$1.run(resttemplatexhrtransport.java:128) ~[spring-websocket-4.2.0.rc1.jar:4.2.0.rc1] @ java.lang.thread.run(thread.java:745) [na:1.8.0_45] 19:56:50.167 [simpleasynctaskexecutor-2] debug o.s.m.simp.stomp.defaultstompsession - failed connect session id=318180fa-47bc-5649-c136-db91a339837a org.springframework.web.client.httpclienterrorexception: 405 method not allowed @ org.springframework.web.client.defaultresponseerrorhandler.handleerror(defaultresponseerrorhandler.java:91) ~[spring-web-4.1.3.release.jar:4.1.3.release] @ org.springframework.web.client.resttemplate.handleresponseerror(resttemplate.java:615) ~[spring-web-4.1.3.release.jar:4.1.3.release] @ org.springframework.web.client.resttemplate.doexecute(resttemplate.java:573) ~[spring-web-4.1.3.release.jar:4.1.3.release] @ org.springframework.web.client.resttemplate.execute(resttemplate.java:544) ~[spring-web-4.1.3.release.jar:4.1.3.release] @ org.springframework.web.socket.sockjs.client.resttemplatexhrtransport$1.run(resttemplatexhrtransport.java:128) ~[spring-websocket-4.2.0.rc1.jar:4.2.0.rc1] @ java.lang.thread.run(thread.java:745) [na:1.8.0_45] 19:56:50.170 [simpleasynctaskexecutor-2] error stompwebsockettestclient - transport error org.springframework.web.client.httpclienterrorexception: 405 method not allowed @ org.springframework.web.client.defaultresponseerrorhandler.handleerror(defaultresponseerrorhandler.java:91) ~[spring-web-4.1.3.release.jar:4.1.3.release] @ org.springframework.web.client.resttemplate.handleresponseerror(resttemplate.java:615) ~[spring-web-4.1.3.release.jar:4.1.3.release] @ org.springframework.web.client.resttemplate.doexecute(resttemplate.java:573) ~[spring-web-4.1.3.release.jar:4.1.3.release] @ org.springframework.web.client.resttemplate.execute(resttemplate.java:544) ~[spring-web-4.1.3.release.jar:4.1.3.release] @ org.springframework.web.socket.sockjs.client.resttemplatexhrtransport$1.run(resttemplatexhrtransport.java:128) ~[spring-websocket-4.2.0.rc1.jar:4.2.0.rc1] @ java.lang.thread.run(thread.java:745) [na:1.8.0_45]
here the spring security configuration file:
@override protected void configure(httpsecurity http) throws exception { http. csrf().disable(). sessionmanagement().sessioncreationpolicy(sessioncreationpolicy.stateless). and(). authorizerequests(). //todo: workaround ws 401 error, tried did not work: antmatchers("/hello").permitall(). possible related stompclient url ws:// antmatchers(actuatorendpoints()).hasrole(backendadminrole). anyrequest().authenticated(). and(). anonymous().disable(). exceptionhandling().authenticationentrypoint(unauthorizedentrypoint()); http.addfilterbefore(new authenticationfilter(authenticationmanager()), basicauthenticationfilter.class). addfilterbefore(new managementendpointauthenticationfilter(authenticationmanager()), basicauthenticationfilter.class); }
please note i'm not using webclient, security configuration disable spring's default spring loginform
here websocket configuration
@override public void configuremessagebroker(messagebrokerregistry config) { config.enablesimplebroker("/topic/"); config.setapplicationdestinationprefixes("/app"); } @override public void registerstompendpoints(stompendpointregistry registry) { registry.addendpoint("/hello").withsockjs(); }
here websocket security configuration (i tried many configurations - tried found in web, didnt work)
@override protected void configureinbound(messagesecuritymetadatasourceregistry messages) { messages // message types other message , subscribe .nulldestmatcher().authenticated() // matches destination starts /rooms/ .simpdestmatchers("/topic/**").authenticated() // (i.e. cannot send messages directly /topic/, /queue/) // (i.e. cannot subscribe /topic/messages/* messages sent // /topic/messages-user<id>) .simptypematchers(simpmessagetype.message, simpmessagetype.subscribe).denyall() // catch .anymessage().denyall(); } /** * disables csrf websockets. */ @override protected boolean sameorigindisabled() { return true; }
and here java client
list<transport> transports = new arraylist<>(2); standardwebsocketclient standardwebsocketclient = new standardwebsocketclient(); transports.add(new websockettransport(standardwebsocketclient)); resttemplatexhrtransport resttemplatexhrtransport = new resttemplatexhrtransport(); //setting authentication token httpheaders httpheaders = new httpheaders(); httpheaders.add("x-auth-token", token); resttemplatexhrtransport.setrequestheaders(httpheaders); transports.add(resttemplatexhrtransport); sockjsclient sockjsclient = new sockjsclient(transports); websocketstompclient stompclient = new websocketstompclient(sockjsclient); threadpooltaskscheduler taskscheduler = new threadpooltaskscheduler(); taskscheduler.afterpropertiesset(); string stompurl = "ws://localhost:9090/hello"; stompclient.setmessageconverter(new stringmessageconverter()); stompclient.settaskscheduler(taskscheduler); stompclient.setdefaultheartbeat(new long[] {10, 10}); websockethttpheaders headers = new websockethttpheaders(httpheaders); websocketsession websocketsession; logger.debug("connecting , subscribing " + number_of_users + " users "); stopwatch stopwatch = new stopwatch("stomp broker relay websocket load tests"); stopwatch.start(); list<consumerstompsessionhandler> consumers = new arraylist<>(); (int i=0; < number_of_users; i++) { consumers.add(new consumerstompsessionhandler(broadcast_message_count, connectlatch, subscribelatch, messagelatch, disconnectlatch, failure)); stompclient.connect(stompurl, headers, consumers.get(i), host, port); }
the application failed on stompclient.connect() line where: host address of web application server (spring base of course) - in case 'localhost'. 'port' parameter port web application server listening on. headers: include 'x-auth-token' header
here current pom.xml i'm using (well, changed bit since wrote post)
<?xml version="1.0" encoding="utf-8"?> <project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelversion>4.0.0</modelversion> <parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifactid> <version>1.1.9.release</version> </parent> <groupid>my-group</groupid> <artifactid>my.id</artifactid> <version>1.0.0</version> <properties> <org.springframework-version>4.1.3.release</org.springframework-version> <app.version>1.0</app.version> <spring-boot.version>1.1.3.release</spring-boot.version> <!-- generic properties --> <java.version>1.8</java.version> <project.build.sourceencoding>utf-8</project.build.sourceencoding> <project.reporting.outputencoding>utf-8</project.reporting.outputencoding> <!-- logging <logback.version>1.0.13</logback.version> <slf4j.version>1.7.5</slf4j.version>--> <log4j.version>1.2.17</log4j.version> <tomcat.version>8.0.8</tomcat.version> <spring.version>4.1.0.release</spring.version> <!-- test --> <junit.version>4.11</junit.version> <springloaded.version>1.2.0.release</springloaded.version> <spring-security.version>4.0.0.rc1</spring-security.version> </properties> <dependencies> <dependency> <groupid>log4j</groupid> <artifactid>log4j</artifactid> <version>${log4j.version}</version> </dependency> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-context</artifactid> <version>${org.springframework-version}</version> <exclusions> <exclusion> <groupid>commons-logging</groupid> <artifactid>commons-logging</artifactid> </exclusion> </exclusions> </dependency> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-websocket</artifactid> <version>${org.springframework-version}</version> </dependency> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-messaging</artifactid> <version>${org.springframework-version}</version> </dependency> <dependency> <groupid>org.springframework.session</groupid> <artifactid>spring-session</artifactid> <version>1.0.1.release</version> </dependency> <dependency> <groupid>org.springframework.session</groupid> <artifactid>spring-session-data-redis</artifactid> <version>1.0.1.release</version> </dependency> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-web</artifactid> <version>4.1.6.release</version> </dependency> <dependency> <groupid>org.springframework.data</groupid> <artifactid>spring-data-redis</artifactid> <version>1.3.0.release</version> </dependency> <dependency> <groupid>redis.clients</groupid> <artifactid>jedis</artifactid> <version>2.4.2</version> </dependency> <dependency> <groupid>redis.embedded</groupid> <artifactid>embedded-redis</artifactid> <version>0.5</version> </dependency> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-webmvc</artifactid> <version>${org.springframework-version}</version> </dependency> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-beans</artifactid> <version>4.1.7.release</version> </dependency> <dependency> <groupid>org.springframework.data</groupid> <artifactid>spring-data-rest-webmvc</artifactid> </dependency> <!-- persistance --> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-data-jpa</artifactid> </dependency> <dependency> <groupid>org.postgresql</groupid> <artifactid>postgresql</artifactid> <version>9.3-1101-jdbc41</version> </dependency> <dependency> <groupid>org.hibernate</groupid> <artifactid>hibernate-validator</artifactid> </dependency> <!-- security --> <dependency> <groupid>org.springframework.security</groupid> <artifactid>spring-security-core</artifactid> <version>${spring-security.version}</version> </dependency> <dependency> <groupid>org.springframework.security</groupid> <artifactid>spring-security-messaging</artifactid> <version>${spring-security.version}</version> </dependency> <dependency> <groupid>org.springframework.security</groupid> <artifactid>spring-security-config</artifactid> <version>${spring-security.version}</version> </dependency> <dependency> <groupid>org.springframework.security</groupid> <artifactid>spring-security-web</artifactid> <version>${spring-security.version}</version> <exclusions> <exclusion> <groupid>org.springframework</groupid> <artifactid>spring-jdbc</artifactid> </exclusion> </exclusions> </dependency> <dependency> <groupid>io.jsonwebtoken</groupid> <artifactid>jjwt</artifactid> <version>0.3</version> </dependency> <dependency> <groupid>net.sf.ehcache</groupid> <artifactid>ehcache-core</artifactid> <version>2.6.11</version> </dependency> <!--aspect--> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-aop</artifactid> </dependency> <!--converters--> <dependency> <groupid>commons-beanutils</groupid> <artifactid>commons-beanutils</artifactid> <version>1.9.0</version> </dependency> <!-- joda time --> <dependency> <groupid>joda-time</groupid> <artifactid>joda-time</artifactid> <version>2.3</version> </dependency> <!-- lombok --> <dependency> <groupid>org.projectlombok</groupid> <artifactid>lombok</artifactid> <version>1.14.8</version> </dependency> <!-- json support --> <dependency> <groupid>com.fasterxml.jackson.module</groupid> <artifactid>jackson-module-jsonschema</artifactid> <version>2.3.0</version> </dependency> <dependency> <groupid>com.fasterxml.jackson.core</groupid> <artifactid>jackson-annotations</artifactid> <version>2.3.3</version> </dependency> <dependency> <groupid>com.jayway.jsonpath</groupid> <artifactid>json-path</artifactid> <version>0.8.1</version> <scope>test</scope> </dependency> <!-- testing --> <dependency> <groupid>org.hamcrest</groupid> <artifactid>hamcrest-all</artifactid> <version>1.3</version> <scope>test</scope> </dependency> <dependency> <groupid>junit</groupid> <artifactid>junit</artifactid> <version>${junit.version}</version> <scope>test</scope> <exclusions> <exclusion> <artifactid>hamcrest-core</artifactid> <groupid>org.hamcrest</groupid> </exclusion> </exclusions> </dependency> <dependency> <groupid>org.mockito</groupid> <artifactid>mockito-core</artifactid> <version>1.9.5</version> <scope>test</scope> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-test</artifactid> </dependency> <dependency> <groupid>org.springframework.security</groupid> <artifactid>spring-security-test</artifactid> <version>4.0.0.m1</version> </dependency> <dependency> <groupid>com.jayway.restassured</groupid> <artifactid>rest-assured</artifactid> <version>2.4.1</version> </dependency> <!--json doc--> <dependency> <groupid>com.mangofactory</groupid> <artifactid>swagger-springmvc</artifactid> <version>0.8.2</version> </dependency> <dependency> <groupid>org.jsondoc</groupid> <artifactid>spring-boot-starter-jsondoc</artifactid> <version>1.1.0</version> </dependency> <dependency> <groupid>org.jsondoc</groupid> <artifactid>jsondoc-ui-webjar</artifactid> <version>1.1.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-maven-plugin</artifactid> <dependencies> <dependency> <groupid>org.springframework</groupid> <artifactid>springloaded</artifactid> <version>${springloaded.version}</version> </dependency> </dependencies> </plugin> <plugin> <artifactid>maven-assembly-plugin</artifactid> <version>2.4</version> <configuration> <descriptor>src/assembly/dep.xml</descriptor> </configuration> </plugin> </plugins> </build> <repositories> <repository> <id>spring-releases</id> <url>https://repo.spring.io/libs-release</url> </repository> <repository> <id>clojars.org</id> <url>http://clojars.org/repo</url> </repository> <repository> <id>closure</id> <url>http://clojars.org/repo</url> </repository> <repository> <id>spring-milestones</id> <url>http://repo.spring.io/milestone</url> <snapshots><enabled>false</enabled></snapshots> <releases><enabled>true</enabled></releases> </repository> <repository> <id>java-net</id> <url>https://maven.java.net/content/repositories/releases</url> </repository> </repositories> <pluginrepositories> <pluginrepository> <id>spring-releases</id> <url>https://repo.spring.io/libs-release</url> </pluginrepository> </pluginrepositories> </project>
thanks in advance help
update
i had below logincontroller part of project controller classes. /authenticate controller related post method of x-auth authentication mechanism used spring security. found out once controlled has been removed project - http 405 not allowed error disappeared. have admit have no clue reason. used trial&error try , find issue 405 error. appreciate if me understand might problem. tnx
package com.iotiki.controller; import org.springframework.beans.factory.annotation.autowired; import org.springframework.security.access.annotation.secured; import org.springframework.web.bind.annotation.requestbody; import org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.requestmethod; import org.springframework.web.bind.annotation.restcontroller; import javax.validation.valid; @restcontroller public class logincontroller { @autowired private loginbusinesslogic loginbusinesslogic; @requestmapping(value=apicontroller.authenticate_url/*"/authenticate"*/,method= requestmethod.post) public string login(@valid @requestbody logindto logindto) throws unauthorizedexception { return "this method should not called, since spring security should take over"; } @requestmapping(method=requestmethod.get) public logindto getlogindto(){ return new logindto(); } }
the problem x-auth-token approach works allowing spring session override httpsession implementation (to in x-auth-token header session id , session in redis). spring security behaves (i.e. tries current user in httpsession).
however, configuration provided (reformatted clarity)
http .csrf().disable() .sessionmanagement() .sessioncreationpolicy(sessioncreationpolicy.stateless). .and() .authorizerequests()
is telling spring security not consult httpsession. fix remove sessionmanagement section.
http .csrf().disable() .authorizerequests()
Comments
Post a Comment