text: // Copyright (c) 2014 The Chromium Authors. All rights reserved.
  // 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_string.h"
  #include "base/base64.h"
  #include "net/test/jni/DummySpnegoAuthenticator_jni.h"
  #include "testing/gtest/include/gtest/gtest.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 = {
      arraysize(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 = NULL;
  }
  
  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() {
  }
  
  base::android::ScopedJavaLocalRef<jstring>
  DummySpnegoAuthenticator::SecurityContextQuery::GetTokenToReturn(
      JNIEnv* env,
      const JavaParamRef<jobject>& /*obj*/) {
    return base::android::ConvertUTF8ToJavaString(env, output_token.c_str());
  }
  int DummySpnegoAuthenticator::SecurityContextQuery::GetResult(
      JNIEnv* /*env*/,
      const JavaParamRef<jobject>& /*obj*/) {
    return response_code;
  }
  
  void DummySpnegoAuthenticator::SecurityContextQuery::CheckGetTokenArguments(
      JNIEnv* env,
      const JavaParamRef<jobject>& /*obj*/,
      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() {
  }
  
  DummySpnegoAuthenticator::~DummySpnegoAuthenticator() {
  }
  
  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));
  }
  
  bool DummySpnegoAuthenticator::RegisterJni(JNIEnv* env) {
    return RegisterNativesImpl(env);
  }
  
  long DummySpnegoAuthenticator::GetNextQuery(
      JNIEnv* /*env*/,
      const JavaParamRef<jobject>& /* obj */) {
    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
  