And, yet another update on this.  The URL/URI that is being processed in the 
authenticateUser function, passed through via the credentials argument, is for 
the /api/tokens location.  Furthermore, I'm proxying Tomcat behind Apache 
HTTPD, so the full URL shows up as:http://localhost:8080/guacamole/api/tokens
and the URI as:/guacamole/api/tokens

This explains why the method is always showing up as POST and why the ticket 
parameter cannot be found.  Any ideas where I should go next in tweaking this?  
Basically when authenticating to CAS you pass a service= parameter in the URL 
that tells CAS what page to call after authentication succeeds.  I currently 
have that set to /guacamole, so CAS authenticates, then calls 
/guacamole?ticket=<TICKET NUMBER> - but that's not what is picked up by this 
function.
-Nick 

    On Wednesday, December 21, 2016 2:06 PM, "[email protected]" 
<[email protected]> wrote:
 
 

 Okay, more progress, here.  Not sure what the issue was with the blank login 
page, but it disappeared on its own.  We'll see if it stays away.
I'm now to the point where I load the Guacamole URL, it redirects to the CAS 
SSO Login page, and then I'm able to input login info.  CAS then redirects back 
to the Guacamole page, at which point I get put into an endless redirection 
loop between CAS, which already has me logged in and issues a ticket, and 
Guacamole, which can't seem to pull the ticket parameter from the request, so 
it sends it back to the CAS login page.  In the URL, I see that CAS has 
appended the ticket= parameter to my Guacamole URL when it redirects back after 
logging in; however, my code cannot seem to see the ticket parameter.  Also, 
when I look at the getMethod() output for the request, it's showing up as a 
POST, not a GET, which I'm guessing is why it isn't seeing the parameter - but 
I don't understand why it would show up as a POST method in the first place??  
If I use the Chrome Developer Console and watch the requests, all I ever see 
are GET methods.  I'm missing something...relevant code is below (added lots of 
logger.debug calls to try to figure out what's going on...).
-Nick     public AuthenticatedUser authenticateUser(Credentials credentials)    
        throws GuacamoleException {
        String ticket = null;        logger.debug("Getting authenticated user 
from credentials: \"{}\"", credentials);
        // Pull CAS ticket from request if present        HttpServletRequest 
request = credentials.getRequest();        if (request != null) {            
logger.debug("This is a \"{}\" request.", request.getMethod()); // This always 
returns POST?!            logger.debug("Request looks good, grabbing parameter 
\"{}\"", CASTicketField.PARAMETER_NAME); // This outputs the correct "ticket" 
parameter.            ticket = 
request.getParameter(CASTicketField.PARAMETER_NAME); // This is always null.    
        if(ticket == null)              logger.debug("Why don't I have a 
ticket?!?!?!?!?!?!");        }
        // If ticket provided, validate and produce authenticated user        
if (ticket != null) {            logger.debug("We have a ticket!!");            
// Create corresponding authenticated user            AuthenticatedUser 
authenticatedUser = authenticatedUserProvider.get();            
authenticatedUser.init(ticketService.processUsername(ticket), credentials);     
       return authenticatedUser;
        }
        // Request CAS ticket        logger.debug("About to request ticket for 
user.");        throw new GuacamoleInvalidCredentialsException("Invalid 
login.",            new CredentialsInfo(Arrays.asList(new Field[] {
                // CAS-specific ticket (will automatically redirect the user    
            // to the authorization page via JavaScript)                new 
CASTicketField(                    confService.getAuthorizationEndpoint(),      
              confService.getRedirectURI()                )
            }))        );
    }
 

    On Wednesday, December 21, 2016 10:27 AM, "[email protected]" 
<[email protected]> wrote:
 
 

 So, I grabbed the OpenID code from your github repo and started hacking away 
at it.  I've managed to get it pretty well configured and compiled, but am 
running into an issue.  The extension loads with the Guacamole web app without 
a problem, but when you load Guacamole in the browser, you just get a blank 
page, and no redirect to the CAS SSO login page.  It looks like it is 
successfully hiding the login box, but not doing the redirect, for one reason 
or another.
For kicks I went ahead and compiled the OpenID extension (had to tweak version 
of 0.9.9-incubating to 0.9.10-incubating), and loaded it, and it seems to 
behave the same way - blank page, no redirect to OpenID login.
So, I'm wondering if something changed 0.9.9 -> 0.9.10 that would be causing 
both the OpenID extension and my CAS extension to behave this way?  I'll 
continue to hack at it and look at the other extensions and see what I can 
figure out.
Thanks,Nick
 

    On Tuesday, December 20, 2016 2:24 PM, "[email protected]" 
<[email protected]> wrote:
 
 

 Thanks, Mike,I'll take a look at your OpenID code and see what I can find.  I 
had just started looking into CAS SSO + AngularJS to see if anyone had done 
that, so maybe between your code and the results I found for CASified AngularJS 
apps I'll be able to get something working.
Thanks for the hints.
-Nick  

    On Tuesday, December 20, 2016 2:19 PM, Mike Jumper 
<[email protected]> wrote:
 
 

 I wouldn't recommend trying to alter the web.xml, nor trying to use JSP. There 
must be a better way.

I'm not familiar with CAS SSO myself, but I did write a proof-of-concept OpenID 
authentication extension for Guacamole which involves a similar flow (redirect 
to third-party site, redirect back):

https://github.com/mike-jumper/guacamole-auth-openid
The implementation hinged on defining a custom field type which the auth 
provider could specify when requesting additional credentials:
https://github.com/mike-jumper/guacamole-auth-openid/blob/348151bd299617e21840a5d526af150016fdcbec/src/main/java/org/glyptodon/guacamole/auth/oauth/form/OAuthTokenField.java

https://github.com/mike-jumper/guacamole-auth-openid/blob/348151bd299617e21840a5d526af150016fdcbec/src/main/java/org/glyptodon/guacamole/auth/oauth/AuthenticationProviderService.java#L107-L120

The field is written to redirect the user appropriately:
https://github.com/mike-jumper/guacamole-auth-openid/blob/348151bd299617e21840a5d526af150016fdcbec/src/main/resources/oauthConfig.js

https://github.com/mike-jumper/guacamole-auth-openid/blob/348151bd299617e21840a5d526af150016fdcbec/src/main/resources/oauthController.js

The abstract concept here is:
1) User visits Guacamole, but is not authenticated.2) The auth provider 
requests the credentials it needs, in this case a validation token from the SSO 
service. A field type is defined which represents this token.3) The field type 
implementation performs the client-side tasks necessary to retrieve that token, 
in this case redirecting the user.4) The SSO service authenticates the user, 
produces the token, and sends the user back to the original site.5) The field 
implementation retrieves the token and forwards it along as the user's 
credentials.6) Authentication succeeds.
Perhaps something like that would work in your case?
- Mike

On Tue, Dec 20, 2016 at 9:43 AM, <[email protected]> wrote:

So, just as a follow-up to this...I looked into a couple of other 
possibilities, but am having trouble making any of them work:- 
web-fragment.xml, a way to add stuff to web.xml without having it actually in 
web.xml.  This looked really promising at first, but it seems that anything JAR 
file providing web-fragment.xml files must be located in the WEB-INF/lib 
directory, and since Guacamole loads authentication extensions from 
GUACAMOLE_HOME/extensions, this doesn't seem to work.- Creating an 
implementation of ServletContextListener and then using the programmatic 
options to add filters to a servlet.  The problem here - the class implementing 
ServletContextListener has to be listed in the web.xml file (or, presumably, 
web-fragment.xml), which makes implementing this as an extension difficult.- 
Some sort of Guice implementation that uses the above method of implementing a 
ServletContextListener and then binding it to a class already implemented in 
the main Guacamole code.  Unfortunately it doesn't appear (to me) that there's 
anything existing that a class like this would bind to, which means 
modification to the existing client code before such an extension would 
actually work.- Figure out a way to implement the logon redirection to CAS SSO 
in JSP rather than using filters.  I'm still working this angle, just don't 
know how possible it actually is.
Other ideas?  Anything I'm missing here?
-Nick 

    On Monday, December 19, 2016 5:51 PM, "[email protected]" 
<[email protected]> wrote:



 Hello, everyone,I've started attempting to write an authentication module for 
Guacamole that integrates with the Apereo CAS SSO product.  I know a person or 
two has already attempted this, but I haven't seen anyone's code, so I'm 
starting from scratch.  I'm struggling a little with how this should integrate 
with the existing Guacamole web client.  In the current client, it seems like 
the client displays the normal username/password box, and credentials are then 
passed back to one or more backend authentication classes.  In implementing a 
CAS SSO module, instead of displaying the login box, the page needs to redirect 
to the SSO login page, which either displays the credential prompt or returns 
an already active SSO session.
In doing some research, it looks as if the preferred method of accomplishing 
this with the CAS SSO Java client is via modifications to the web.xml file - 
adding login filters to that.  I'm not entirely sure if this is "compatible" 
with how extensions are currently implemented in the Guacamole web client - if 
there's any way to have an extension add to the web.xml file?  I've managed to 
get SSO to work (mostly) by manually adding these filters to the web.xml and 
then writing a very basic authentication extension that grabs the username from 
the HTTP session and returns an empty <String, GuacamoleConfiguration> map.  
It's a work in progress :-).
So, my first question is, is there a different way i should be going about 
having the existing Guacamole web client bypass the username/password dialog 
and redirect to the SSO login page?  If the web.xml file is the preferred way, 
is there a way I should go about overriding the existing one via an extension?
Second, for the extension class for the backend portion of the authentication, 
is there something more secure I should be doing with the SSO stuff than just 
grabbing the current session username - trying to get and verify the ticket or 
something like that?  Or is this good enough given that the login page 
redirects to SSO?
Thanks, and go easy on a newbie Guac/Java developer :-).
-Nick


   



 
  

 
  

 
  

 
   

Reply via email to