1

sorry for my bad language at first. I am a student from Germany und new in programming.

I have implemented a little websocket server with Spring Boot and secured it with Spring Security using Basic Auth. Angular 2 is used in the Front End. I have implemented the following solution to connect to the websocket.

 * Connects to a websocket server.
 * @param  {string} url     The url of the WS Server
 * @param  {string} channel The channel to subscribe
 * @return {boolean} connection status
 */
public connect(url: string, channel: string): boolean {
    console.group('WebSocketService: Welcome to the connect function.');
    console.log('Connects to', url);
    console.log('Channel is', channel);
    let _self = this;
    let socket = new SockJS(url);
    _self.wsClient = Stomp.over(socket);

    _self.wsClient.connect({}, function(frame) {
        _self.setConnected(true);
        console.log('Connected: ', frame);
        _self.wsClient.subscribe(channel, function(greeting) {
            console.log(greeting);
            _self.subjects[channel].next(greeting);
        });
    });
    console.groupEnd();
    return true;
}

Calling this function let the browser open an input for username and password. Now i can connect and disconnect from the Server with no need to enter the username / password again.

How can i replace this browser input window with using login information in the code?

I tried to do this by a single Post request like:

private test2(){
  let username : string = 'admin';
  let password : string = 'pass';
  let headers = new Headers();
  headers.append("Authorization", "Basic " + btoa(username + ":" + password));
  headers.append("Content-Type", "application/x-www-form-urlencoded");
  console.log('Test beginnt');
  return this._http.get('http://localhost:8080/gs-guide-websocket', {headers: headers}).map(res=> console.log(res))
}

Blockquote

But this gives me only an http 200 response and did not open a session or something.

I have tried to put the login information in the original request also.

_self.wsClient.connect('admin','pass', function(frame) { ...}

Thank you for your help.

1 Answer 1

1

I haven't work with SockJS. But I have implemented some small mechanism for pure WebSocket. Maybe it will be helpful

First of all, OAUTH configuration:

@Configuration
@EnableAuthorizationServer
@EnableResourceServer
public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {

    private static Logger logger = LoggerFactory.getLogger(OAuth2Configuration.class);
    private UsersService service = new UsersService();

    @Autowired
    AuthenticationManagerBuilder authenticationManager;

    @Autowired
    UserDetailsService userDetailsService;


    @Override
    public void configure( AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

        authenticationManager.userDetailsService(this.userDetailsService);
        endpoints.authenticationManager((Authentication authentication) ->  authenticationManager.getOrBuild().authenticate(authentication));
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory().withClient("application_name")
                .authorizedGrantTypes("password", "authorization_code", "refresh_token")
                .scopes("write", "read", "trust")
                .secret("secret").accessTokenValiditySeconds(24 * 60 * 60);
    }

    @Bean
    public UserDetailsService userDetailsService() {
        return (username) -> {
            return service.getByName(username).map(account -> new User(account.getName(), account.getPassword(), account.getAuthorities())).orElseThrow(
                    () -> new RuntimeException("User not found")
            );
        };
    }
}

second, angular2 authorization:

let headers = new Headers();
headers.append("Authorization", "Basic appname:secret");
this.http.post("localhost:8080/oauth_endpoint?grant_type=password&scope=trust&username=" + login + "&password=" + password , "", { headers: headers })
      .map((response: Response) => response.json())
      .subscribe(response => {
          this.accessToken = response.access_token; //will be used for socket
        }
    );

third socket configuration:

@Configuration
@EnableWebSocket
public class SocketConfig implements WebSocketConfigurer {

    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(socketHandler(), "/websocket").setAllowedOrigins("*");
    }

    @Bean
    public SocketHandler socketHandler() {
        return new SocketHandler();
    }
}

public class SocketHandler extends TextWebSocketHandler {

    @Autowired
    private CheckTokenEndpoint checkTokenEndpoint;

    private static Logger logger = LoggerFactory.getLogger(SocketHandler.class);


    public void afterConnectionEstablished(WebSocketSession session) {
        logger.info("New peer connected: " + session.getId());
    }

    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        logger.debug("Peer is trying to authenticate");
        String token = message.getPayload().toString();
        try {
            checkTokenEndpoint.checkToken(token);
            logger.info("New peer authenticated. ");
        } catch (Exception e) {
            logger.warn("Peer unauthenticated!");
            session.close(); //closing connection when provided token doesn't match
        }
    }
}

and last, establishing connection via angular2:

let ws = new WebSocket("localhost:8080/websocket", []);
ws.onopen = (event: Event) => {
      this.send(
          ws.send()

      });

This code may not work if you just copy/paste. I had several other cases to deal with (ie my websocket is reestablishing connection). Because they are out of the question scope, I removed them manually while placing code here.

Sign up to request clarification or add additional context in comments.

1 Comment

This is basically what I've been searching for. Could you please elaborate on the CheckTokenEndpoint? Is it enough to send the token in the Authorization header, and will it be picked up by Spring Security automatically?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.