Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions guacamole/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,5 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,23 @@ public class APIAuthenticationResult {
*/
private final List<String> availableDataSources;

/**
* The baseUrl injected by the requester to be returned for load balancing purposes.
*/
private final String baseUrl;


/**
* Returns the baseUrl that should be used by the client for subsequent requests,
* if any. This is typically used for load balancing or redirection.
*
* @return
* The baseUrl to be used, or null if no specific baseUrl is required.
*/
public String getBaseUrl() {
return baseUrl;
}

/**
* Returns the unique authentication token which identifies the current
* session.
Expand Down Expand Up @@ -118,10 +135,39 @@ public List<String> getAvailableDataSources() {
*/
public APIAuthenticationResult(String authToken, String username,
String dataSource, List<String> availableDataSources) {
// Chain to the new constructor with null for baseUrl
this(authToken, username, dataSource, availableDataSources, null);
}

/**
* Create a new APIAuthenticationResult object containing the given data.
*
* @param authToken
* The unique token generated for the user that authenticated, to be
* used for the duration of their session.
*
* @param username
* The username of the user owning the given token.
*
* @param dataSource
* The unique identifier of the AuthenticationProvider which
* authenticated the user.
*
* @param availableDataSources
* The unique identifier of all AuthenticationProviders to which the
* user now has access.
*
* @param baseUrl
* The base URL that the client should use for subsequent requests,
* or null if the standard URL should be used.
*/
public APIAuthenticationResult(String authToken, String username,
String dataSource, List<String> availableDataSources, String baseUrl) {
this.authToken = authToken;
this.username = username;
this.dataSource = dataSource;
this.availableDataSources = Collections.unmodifiableList(availableDataSources);
this.baseUrl = baseUrl;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@
import javax.ws.rs.core.MultivaluedMap;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleResourceNotFoundException;
import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.Credentials;
import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.properties.StringGuacamoleProperty;
import org.apache.guacamole.GuacamoleSession;
import org.apache.guacamole.rest.APIRequest;
import org.slf4j.Logger;
Expand All @@ -62,6 +64,25 @@ public class TokenRESTService {
@Inject
private AuthenticationService authenticationService;

/**
* The Guacamole server environment.
*/
@Inject
private Environment environment;

/**
* The property within guacamole.properties which defines the HTTP header
* that contains the client base URL (for service discovery/load balancing).
*/
private static final StringGuacamoleProperty AUTH_BASE_URL_HEADER = new StringGuacamoleProperty() {

@Override
public String getName() {
return "auth-base-url-header";
}

};

/**
* Returns the credentials associated with the given request, using the
* provided username and password.
Expand Down Expand Up @@ -173,6 +194,19 @@ public APIAuthenticationResult createToken(@FormParam("username") String usernam
// Create/update session producing possibly-new token
token = authenticationService.authenticate(credentials, token);

// Determine if a custom Base URL should be injected
String baseUrl = null;

// Use the injected environment instead of static access
String headerName = environment.getProperty(AUTH_BASE_URL_HEADER);

if (headerName != null) {
String headerValue = request.getHeader(headerName);
if (headerValue != null) {
baseUrl = headerValue.replace("{TOKEN}", token);
}
}

// Pull corresponding session
GuacamoleSession session = authenticationService.getGuacamoleSession(token);
if (session == null)
Expand All @@ -190,7 +224,8 @@ public APIAuthenticationResult createToken(@FormParam("username") String usernam
token,
authenticatedUser.getIdentifier(),
authenticatedUser.getAuthenticationProvider().getIdentifier(),
authProviderIdentifiers
authProviderIdentifiers,
baseUrl
);

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.guacamole.rest.auth;

import java.util.Collections;
import org.junit.Test;
import static org.junit.Assert.*;

public class APIAuthenticationResultTest {

/**
* Verifies that the baseUrl is correctly stored and retrieved when
* using the new constructor.
*/
@Test
public void testBaseUrlInjection() {
String expectedUrl = "https://lb.example.com";
APIAuthenticationResult result = new APIAuthenticationResult(
"token",
"user",
"source",
Collections.emptyList(),
expectedUrl
);

assertEquals(expectedUrl, result.getBaseUrl());
}

/**
* Verifies that the legacy constructor still works and results in a
* null baseUrl (backward compatibility).
*/
@Test
public void testLegacyConstructor() {
APIAuthenticationResult result = new APIAuthenticationResult(
"token",
"user",
"source",
Collections.emptyList()
);

assertNull(result.getBaseUrl());
}
}