chromium/net/android/dummy_spnego_authenticator.cc

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/android/dummy_spnego_authenticator.h"

#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/base64.h"
#include "testing/gtest/include/gtest/gtest.h"

// Must come after all headers that specialize FromJniType() / ToJniType().
#include "net/android/dummy_spnego_authenticator_jni/DummySpnegoAuthenticator_jni.h"

using base::android::JavaParamRef;

namespace net {

// iso.org.dod.internet.security.mechanism.snego (1.3.6.1.5.5.2)
// From RFC 4178, which uses SNEGO not SPNEGO.
static const unsigned char kSpnegoOid[] = {0x2b, 0x06, 0x01, 0x05, 0x05, 0x02};
gss_OID_desc CHROME_GSS_SPNEGO_MECH_OID_DESC_VAL = {
    std::size(kSpnegoOid), const_cast<unsigned char*>(kSpnegoOid)};

gss_OID CHROME_GSS_SPNEGO_MECH_OID_DESC = &CHROME_GSS_SPNEGO_MECH_OID_DESC_VAL;

namespace {

// gss_OID helpers.
// NOTE: gss_OID's do not own the data they point to, which should be static.
void ClearOid(gss_OID dest) {
  if (!dest)
    return;
  dest->length = 0;
  dest->elements = nullptr;
}

void SetOid(gss_OID dest, const void* src, size_t length) {
  if (!dest)
    return;
  ClearOid(dest);
  if (!src)
    return;
  dest->length = length;
  if (length)
    dest->elements = const_cast<void*>(src);
}

void CopyOid(gss_OID dest, const gss_OID_desc* src) {
  if (!dest)
    return;
  ClearOid(dest);
  if (!src)
    return;
  SetOid(dest, src->elements, src->length);
}

}  // namespace

namespace test {

GssContextMockImpl::GssContextMockImpl()
    : lifetime_rec(0), ctx_flags(0), locally_initiated(0), open(0) {
  ClearOid(&mech_type);
}

GssContextMockImpl::GssContextMockImpl(const GssContextMockImpl& other)
    : src_name(other.src_name),
      targ_name(other.targ_name),
      lifetime_rec(other.lifetime_rec),
      ctx_flags(other.ctx_flags),
      locally_initiated(other.locally_initiated),
      open(other.open) {
  CopyOid(&mech_type, &other.mech_type);
}

GssContextMockImpl::GssContextMockImpl(const char* src_name_in,
                                       const char* targ_name_in,
                                       uint32_t lifetime_rec_in,
                                       const gss_OID_desc& mech_type_in,
                                       uint32_t ctx_flags_in,
                                       int locally_initiated_in,
                                       int open_in)
    : src_name(src_name_in ? src_name_in : ""),
      targ_name(targ_name_in ? targ_name_in : ""),
      lifetime_rec(lifetime_rec_in),
      ctx_flags(ctx_flags_in),
      locally_initiated(locally_initiated_in),
      open(open_in) {
  CopyOid(&mech_type, &mech_type_in);
}

GssContextMockImpl::~GssContextMockImpl() {
  ClearOid(&mech_type);
}

}  // namespace test

namespace android {

DummySpnegoAuthenticator::SecurityContextQuery::SecurityContextQuery(
    const std::string& in_expected_package,
    uint32_t in_response_code,
    uint32_t in_minor_response_code,
    const test::GssContextMockImpl& in_context_info,
    const std::string& in_expected_input_token,
    const std::string& in_output_token)
    : expected_package(in_expected_package),
      response_code(in_response_code),
      minor_response_code(in_minor_response_code),
      context_info(in_context_info),
      expected_input_token(in_expected_input_token),
      output_token(in_output_token) {
}

DummySpnegoAuthenticator::SecurityContextQuery::SecurityContextQuery(
    const std::string& in_expected_package,
    uint32_t in_response_code,
    uint32_t in_minor_response_code,
    const test::GssContextMockImpl& in_context_info,
    const char* in_expected_input_token,
    const char* in_output_token)
    : expected_package(in_expected_package),
      response_code(in_response_code),
      minor_response_code(in_minor_response_code),
      context_info(in_context_info) {
  if (in_expected_input_token)
    expected_input_token = in_expected_input_token;
  if (in_output_token)
    output_token = in_output_token;
}

DummySpnegoAuthenticator::SecurityContextQuery::SecurityContextQuery()
    : response_code(0), minor_response_code(0) {
}

DummySpnegoAuthenticator::SecurityContextQuery::SecurityContextQuery(
    const SecurityContextQuery& other) = default;

DummySpnegoAuthenticator::SecurityContextQuery::~SecurityContextQuery() =
    default;

base::android::ScopedJavaLocalRef<jstring>
DummySpnegoAuthenticator::SecurityContextQuery::GetTokenToReturn(JNIEnv* env) {
  return base::android::ConvertUTF8ToJavaString(env, output_token.c_str());
}
int DummySpnegoAuthenticator::SecurityContextQuery::GetResult(JNIEnv* /*env*/) {
  return response_code;
}

void DummySpnegoAuthenticator::SecurityContextQuery::CheckGetTokenArguments(
    JNIEnv* env,
    const JavaParamRef<jstring>& j_incoming_token) {
  std::string incoming_token =
      base::android::ConvertJavaStringToUTF8(env, j_incoming_token);
  EXPECT_EQ(expected_input_token, incoming_token);
}

// Needed to satisfy "complex class" clang requirements.
DummySpnegoAuthenticator::DummySpnegoAuthenticator() = default;

DummySpnegoAuthenticator::~DummySpnegoAuthenticator() = default;

void DummySpnegoAuthenticator::EnsureTestAccountExists() {
  Java_DummySpnegoAuthenticator_ensureTestAccountExists(
      base::android::AttachCurrentThread());
}

void DummySpnegoAuthenticator::RemoveTestAccounts() {
  Java_DummySpnegoAuthenticator_removeTestAccounts(
      base::android::AttachCurrentThread());
}

void DummySpnegoAuthenticator::ExpectSecurityContext(
    const std::string& expected_package,
    uint32_t response_code,
    uint32_t minor_response_code,
    const test::GssContextMockImpl& context_info,
    const std::string& expected_input_token,
    const std::string& output_token) {
  SecurityContextQuery query(expected_package, response_code,
                             minor_response_code, context_info,
                             expected_input_token, output_token);
  expected_security_queries_.push_back(query);
  Java_DummySpnegoAuthenticator_setNativeAuthenticator(
      base::android::AttachCurrentThread(), reinterpret_cast<intptr_t>(this));
}

long DummySpnegoAuthenticator::GetNextQuery(JNIEnv* /*env*/) {
  CheckQueueNotEmpty();
  current_query_ = expected_security_queries_.front();
  expected_security_queries_.pop_front();
  return reinterpret_cast<intptr_t>(&current_query_);
}

void DummySpnegoAuthenticator::CheckQueueNotEmpty() {
  ASSERT_FALSE(expected_security_queries_.empty());
}

}  // namespace android
}  // namespace net