send method

  1. @override
Future<StreamedResponse> send(
  1. BaseRequest originalReq
)

Function that actually does the NTLM authentication.

This function generates the headers required to authenticate based on previous responses.

Implementation

@override
Future<StreamedResponse> send(BaseRequest originalReq) async {
  // We need to be able to send a copy of the request with the Type 3 message
  // header attached. Since request bodies can only be streamed once, read the
  // entire body now so we can create request copies later on.
  final body = await originalReq.finalize().toBytes();

  // 1. Send the initial request
  final msg1 = createType1Message(
    domain: domain,
    workstation: workstation,
    headerPrefix: headerPrefix,
  );

  final req2 = _copyRequest(originalReq, body);
  req2.headers[_authorizationHeader] = msg1;
  final res2 = await _inner.send(req2);

  // 2. Parse the Type 2 message
  final res2Authenticate = res2.headers[_wwwAuthenticateHeader];
  // If the initial request was successful or this isn't an NTLM request,
  // return the initial response
  if (res2.statusCode == 200 || res2Authenticate == null) return res2;
  // Servers may support multiple authentication methods so we need to find
  // the correct one
  final res2AuthenticateParts = res2Authenticate.split(',');
  String? rawMsg2;
  for (var res2AuthenticatePart in res2AuthenticateParts) {
    var trimmedPart = res2AuthenticatePart.trim();
    if (trimmedPart.startsWith('$headerPrefix ')) {
      rawMsg2 = trimmedPart;
      break;
    }
  }
  // If this isn't an NTLM request, return the initial response
  if (rawMsg2 == null) return res2;
  final msg2 = parseType2Message(
    rawMsg2,
    headerPrefix: headerPrefix,
  );
  // Discard the body so we can reuse the connection (required by NTLM)
  await res2.stream.drain();

  // 3. Send the authenticated request
  final msg3 = createType3Message(
    msg2,
    domain: domain,
    workstation: workstation,
    username: username,
    password: password,
    lmPassword: lmPassword,
    ntPassword: ntPassword,
    headerPrefix: headerPrefix,
  );

  final req3 = _copyRequest(originalReq, body);
  req3.headers[_authorizationHeader] = msg3;
  final res3 = await _inner.send(req3);

  return res3;
}