Secure Your Flash Client
Before you add security to your clients, follow the steps in Checklist: Configure Authentication and Authorization to set up security on Kaazing WebSocket Gateway for your client. The authentication and authorization methods configured on the Gateway influence your client's security implementation. For information on secure network connections between clients and the Gateway, see Checklist: Secure Network Traffic with the Gateway.
Before You Begin
This procedure is part of Checklist: Build Flash Clients Using Kaazing WebSocket Gateway:
- Set Up Your Development Environment
- Interact with Kaazing WebSocket Gateway Using the WebSocket API
- Interact with Kaazing WebSocket Gateway Using the EventSource API
- Secure Your Flash Client
- Display Logs for the Flash Client
- Troubleshoot Your Flash Client
To Secure Your Flash Client
This section contains the following topics:
- Creating a Basic Challenge Handler
- Using Wildcards to Match Sub-domains and Paths
- Creating a Basic Login Handler
- Creating a More Complex Login Handler
- Managing Log In Attempts
- Creating Kerberos Challenge Handlers
- Directly Establish a Global Kerberos Challenge Handler
- Directly Establish a Global Kerberos Challenge Handler for a Specific Location
- Implementing a Global Negotiate HTTP Authentication Strategy
- Implementing a Negotiate HTTP Authentication Strategy for a Specific Location
Authenticating your client involves implementing a challenge handler to respond to authentication challenges from the Gateway. If your challenge handler is responsible for obtaining user credentials, then you will also need to implement a login handler.
Note: To use the Kaazing WebSocket Gateway Flash client security library, ensure you add the following argument to the Flash compiler:
-include-libraries
GATEWAY_HOME/lib/client/flash/com.kaazing.gateway.client.swc
If you built your application using Flash Builder, you can do this by choosing Project > Properties. In the dialog, choose Flex Compiler, then add the argument to the Additional compiler arguments text box. Otherwise, add the argument to the Flash compiler manually.
Creating a Basic Challenge Handler
A challenge handler is a constructor used in an application to respond to authentication challenges from the Gateway when the application attempts to access a protected resource. Each of the resources protected by the Gateway is configured with a different authentication scheme (for example, Basic, Application Basic, Application Negotiate, or Application Token), and your application requires a challenge handler for each of the schemes that it will encounter or a single challenge handler that will respond to all challenges. Also, you can add a dispatch challenge handler to route challenges to specific challenge handlers according to the URI of the requested resource.
For information about each authentication scheme type, see Configure the HTTP Challenge Scheme.
Clients with a single challenge handling strategy for all 401 challenges can simply set a specific challenge handler as the default using ChallengeHandlers.setDefault(). The following is an example of how to implement the authentication challenge in your client taken from the out of the box Flash & Flex demo at http://localhost:8001/demo/:
// Configure a Basic Challenge Handler var basicHandler:BasicChallengeHandler = new DefaultBasicChallengeHandler(); basicHandler.setLoginHandler(new DemoLoginHandler(this)); ChallengeHandlers.setDefault(basicHandler);
For a complete example of a Flash client using security, see the out of the box demos located in GATEWAY_HOME/demo/flash.
Note: When using a BasicChallengeHandler
, you must load the DefaultBasicChallengeHandler
. To do so, either explicitly set this in your code (as shown in the previous code example), or add the necessary compiler argument to Flash Builder by going to Project Properties > Build path > Flex compiler and typing following into the Additional Compiler Arguments text box:
-includes com.kaazing.gateway.client.security.impl.DefaultBasicChallengeHandler
Here is an example of how to set a global challenge handler declaratively:
var loginHandler:LoginHandler = new SampleLoginHandler1(); ChallengeHandlers.setDefault( (ChallengeHandlers.load(BasicChallengeHandler) as BasicChallengeHandler) .setLoginHandler(loginHandler)
The following example demonstrates how to register a location-specific challenge handler:
var dispatchChallengeHandler:DispatchChallengeHandler = ChallengeHandlers.load(DispatchChallengeHandler); var basicChallengeHandler:BasicChallengeHandler = ChallengeHandlers.load(BasicChallengeHandler); basicChallengeHandler.loginHandler = new SampleLoginHandler1(); dispatchChallengeHandler.register("ws://my.server.com", basicChallengeHandler); ChallengeHandlers.setDefault(dispatchChallengeHandler);
Here is how to register a location-specific challenge handler declaratively:
ChallengeHandlers.setDefault(ChallengeHandlers.load(DispatchChallengeHandler) .register("ws://my.server.com", (ChallengeHandlers.load(BasicChallengeHandler) as BasicChallengeHandler) .setLoginHandler(new SampleLoginHandler1())) );
To following example demonstrates how to register multiple location-specific challenge handlers declaratively:
var myServerLoginHandler:LoginHandler = new SampleLoginHandler1(); var anotherServerLoginHandler:LoginHandler = new SampleLoginHandler2(); ChallengeHandlers.setDefaultImplementation(ChallengeHandler, SampleChallengeHandler); ChallengeHandlers.setDefault(ChallengeHandlers.load(DispatchChallengeHandler) .register("ws://my.server.com", (ChallengeHandlers.load(BasicChallengeHandler) as BasicChallengeHandler) .setLoginHandler(myServerLoginHandler)) .register("ws://another.server.com", (ChallengeHandlers.load(ChallengeHandler) as SampleChallengeHandler) .setLoginHandler(anotherServerLoginHandler)) );
Using Wildcards to Match Sub-domains and Paths
You can use wildcards (“*”) when registering locations using DispatchChallengeHandler. Some examples of locationDescription values with wildcards are:
- */ matches all requests to any host on port 80 (default port), with no user information or path specified.
- *.hostname.com:8000 matches all requests to port 8000 on any sub-domain of hostname.com, but not hostname.com itself.
- server.hostname.com:*/* matches all requests to a particular server on any port on any path but not the empty path.
Creating a Basic Login Handler
The following example demonstrates how to implement a login handler in your client:
// Implement a login handler class public class SampleLoginHandler extends LoginHandler { public function SampleLoginHandler() { super(this); } override public function getCredentials(continuation:Function):void { continuation("joe", "welcome"); } }
Creating a More Complex Login Handler
The following example implements a more complex login handler to restrict login attempts to 3:
package com.kaazing.gateway.client.security.demo { import com.kaazing.gateway.client.security.LoginHandler; import flash.display.DisplayObject; import flash.utils.ByteArray; import mx.managers.PopUpManager; public class LimitedRetriesDemoLoginHandler extends LoginHandler { private var displayObject: DisplayObject; private const LIMIT: int = 3; private var attempts: int = 0; public function LimitedRetriesDemoLoginHandler(displayObject: DisplayObject) { super(this); this.displayObject = displayObject; } override public function getCredentials(continuation:Function):void { attempts++; if ( attempts > LIMIT ) { // send an event perhaps to notify the wider application of attempt violation attempts = 0; continuation(null, null); } else { var loginWindow:LoginForm=LoginForm(PopUpManager.createPopUp(displayObject, LoginForm, false)); PopUpManager.centerPopUp(loginWindow); loginWindow.continuation = continuation; } } } }
Managing Log In Attempts
As displayed above, when it is not possible for the Kaazing WebSocket Gateway client to create a challenge response, the client must return null
to the Gateway to stop the Gateway from continuing to issue authentication challenges.
The following sample taken from Creating a More Complex Login Handler demonstrates how to stop the Gateway from issuing further challenges.
if ( attempts > LIMIT ) { // send an event perhaps to notify the wider application of attempt violation attempts = 0; continuation(null, null); } else { var loginWindow:LoginForm=LoginForm(PopUpManager.createPopUp(displayObject, LoginForm, false)); PopUpManager.centerPopUp(loginWindow); loginWindow.continuation = continuation; }
Creating Kerberos Challenge Handlers
The following examples demonstrate different implementations of Kerberos challenge handlers. When registered with the DispatchChallengeHandler, a KerberosChallengeHandler directly responds to Negotiate challenges where Kerberos-generated authentication credentials are required. In addition, a KerberosChallengeHandler can be used indirectly in conjunction with a NegotiateChallengeHandler to assist in the construction of a challenge response using object identifiers. For more information, see the ActionScript Client API.
Directly Establish a Global Kerberos Challenge Handler
The following example uses KerberosChallengeHandler to create a global Kerberos challenge handler:
var loginHandler:LoginHandler = new SampleLoginHandler1(); ChallengeHandlers.setDefault( (ChallengeHandlers.load(KerberosChallengeHandler) as KerberosChallengeHandler) .setLoginHandler(loginHandler));
Directly Establish a Global Kerberos Challenge Handler for a Specific Location
The following example uses the register() method to establish a challenge handler for a specific location:
var loginHandler:LoginHandler = new SampleLoginHandler1(); ChallengeHandlers.setDefault( (ChallengeHandlers.load(DispatchChallengeHandler) as DispatchChallengeHandler) .register("ws://some.server.com:8010/kerberos5", (ChallengeHandlers.load(KerberosChallengeHandler) as KerberosChallengeHandler) .setDefaultLocation("ws://kb.hostname.com/kerberos5") .setRealmLocation("ATHENA.MIT.EDU", "ws://athena.hostname.com/kerberos5") .setServiceName("HTTP/servergw.hostname.com") .setLoginHandler(loginHandler)) );
Creating a Global Negotiate HTTP Authentication Strategy
The following example establishes a single HTTP authentication strategy for all challenges.
var loginHandler:LoginHandler = new SampleLoginHandler1(); ChallengeHandlers.setDefault( (ChallengeHandlers.load(NegotiateChallengeHandler) as NegotiateChallengeHandler) .register((ChallengeHandlers.load(KerberosChallengeHandler) as KerberosChallengeHandler) .setLoginHandler(loginHandler)) // register additional alternatives to negotiate here. );
Creating a Negotiate HTTP Authentication Strategy for a Specific Location
The following example uses the register() method to establish a location-specific negotiate HTTP authentication strategy:
var loginHandler:LoginHandler = new SampleLoginHandler1(); ChallengeHandlers.setDefault( (ChallengeHandlers.load(DispatchChallengeHandler) as DispatchChallengeHandler) .register("ws://some.server.com", (ChallengeHandlers.load(NegotiateChallengeHandler) as NegotiateChallengeHandler) .register((ChallengeHandlers.load(KerberosChallengeHandler) as KerberosChallengeHandler) .setDefaultLocation("ws://kb.hostname.com/kerberos5") .setRealmLocation("ATHENA.MIT.EDU", "ws://athena.hostname.com/kerberos5") .setServiceName("HTTP/servergw.hostname.com") .setLoginHandler(loginHandler)) // register additional alternatives to negotiate here. ) );