Skip to content

Commit

Permalink
BL-977 - Implement Basic Auth
Browse files Browse the repository at this point in the history
  • Loading branch information
jclausen committed Jan 23, 2025
1 parent c7d1b7d commit a99db33
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 3 deletions.
25 changes: 22 additions & 3 deletions src/main/java/ortus/boxlang/runtime/components/net/HTTP.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -70,6 +71,10 @@
@BoxComponent( allowsBody = true )
public class HTTP extends Component {

private final static String BASIC_AUTH_DELIMITER = ":";
private static final String AUTHMODE_BASIC = "BASIC";
private static final String AUTHMODE_NTLM = "NTLM";

/**
* --------------------------------------------------------------------------
* Constructor(s)
Expand Down Expand Up @@ -131,9 +136,10 @@ public HTTP() {
new Attribute( Key.path, "string", Set.of( Validator.requires( Key.file ) ) ),
new Attribute( Key.clientCert, "string" ),
new Attribute( Key.compression, "string" ),
new Attribute( Key.authType, "string", "BASIC", Set.of( Validator.REQUIRED, Validator.NON_EMPTY, Validator.valueOneOf( "BASIC", "NTLM" ) ) ),
new Attribute( Key.domain, "string" ),
new Attribute( Key.workstation, "string" ),
new Attribute( Key.authType, "string", AUTHMODE_BASIC,
Set.of( Validator.REQUIRED, Validator.NON_EMPTY, Validator.valueOneOf( AUTHMODE_BASIC, AUTHMODE_NTLM ) ) ),
new Attribute( Key.domain, "string", Set.of( Validator.NOT_IMPLEMENTED ) ),
new Attribute( Key.workstation, "string", Set.of( Validator.NOT_IMPLEMENTED ) ),
new Attribute( Key.cachedWithin, "string" ),
new Attribute( Key.encodeUrl, "boolean", true, Set.of( Validator.TYPE ) ),
};
Expand Down Expand Up @@ -167,6 +173,7 @@ public BodyResult _invoke( IBoxContext context, IStruct attributes, ComponentBod
Array params = executionState.getAsArray( Key.HTTPParams );
Struct HTTPResult = new Struct();
URI targetURI = null;
String authMode = attributes.getAsString( Key.authType ).toUpperCase();

try {
HttpRequest.Builder builder = HttpRequest.newBuilder();
Expand All @@ -175,6 +182,18 @@ public BodyResult _invoke( IBoxContext context, IStruct attributes, ComponentBod
List<IStruct> formFields = new ArrayList<>();
List<IStruct> files = new ArrayList<>();
builder.header( "User-Agent", "BoxLang" );
if ( attributes.get( Key.username ) != null && attributes.get( Key.password ) != null ) {
if ( authMode.equals( AUTHMODE_BASIC ) ) {
String auth = attributes.getAsString( Key.username )
+ BASIC_AUTH_DELIMITER
+ StringCaster.cast( attributes.getOrDefault( Key.password, "" ) );
String encodedAuth = Base64.getEncoder().encodeToString( auth.getBytes() );
} else if ( authMode.equals( AUTHMODE_NTLM ) ) {
// TODO: This will need to be implemented as separate type of smb request
throw new BoxRuntimeException( "NTLM authentication is not currently supported." );
}
System.out.println( "Using HTTP Basic Auth" );
}

for ( Object p : params ) {
IStruct param = StructCaster.cast( p );
Expand Down
36 changes: 36 additions & 0 deletions src/test/java/ortus/boxlang/runtime/components/net/HTTPTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.Base64;

import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
import com.github.tomakehurst.wiremock.junit5.WireMockTest;

Expand Down Expand Up @@ -575,4 +577,38 @@ public void testMultipart( WireMockRuntimeInfo wmRuntimeInfo ) {
assertThat( bxhttp.get( Key.fileContent ) ).isEqualTo( "{\"success\": true }" );
}

@DisplayName( "It can process a basic authentication request" )
@Test
public void testBasicAuth( WireMockRuntimeInfo wmRuntimeInfo ) {
String username = "admin";
String password = "password";
String base64Credentials = Base64.getEncoder().encodeToString( ( username + ":" + password ).getBytes() );
stubFor(
get( "/posts/1" )
.willReturn( ok()
.withHeader( "Authorization", "Basic " + base64Credentials )
.withHeader( "Content-Type", "application/json; charset=utf-8" )
.withBody(
"""
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\\nsuscipit recusandae consequuntur expedita et cum\\nreprehenderit molestiae ut ut quas totam\\nnostrum rerum est autem sunt rem eveniet architecto"
}
""" ) ) );

instance.executeSource(
String.format( """
<cfhttp result="result" url="%s" username="%s" password="%s"></bxhttp>
""",
wmRuntimeInfo.getHttpBaseUrl() + "/posts/1",
username,
password
),
context, BoxSourceType.CFTEMPLATE );

assertThat( variables.get( result ) ).isInstanceOf( IStruct.class );
}

}

0 comments on commit a99db33

Please sign in to comment.