jni: Support specifying ServerAuthorizers from Java. 

MultiPart: 1/2

Change-Id: I8a817f10da1025b2d41388a66e1acb7d6f87a426
diff --git a/impl/google/rpc/jni.go b/impl/google/rpc/jni.go
index eec488e..243cc28 100644
--- a/impl/google/rpc/jni.go
+++ b/impl/google/rpc/jni.go
@@ -13,7 +13,6 @@
 	"v.io/v23/context"
 	"v.io/v23/options"
 	"v.io/v23/rpc"
-	"v.io/v23/security"
 	"v.io/v23/vdl"
 	"v.io/v23/vom"
 
@@ -242,21 +241,15 @@
 	return args, nil
 }
 
-func doStartCall(ctx *context.T, cancel func(), name, method string, skipServerAuth bool, goPtr C.jlong, args []interface{}) (jutil.Object, error) {
-	var opts []rpc.CallOpt
-	if skipServerAuth {
-		opts = append(opts,
-			options.NameResolutionAuthorizer{security.AllowEveryone()},
-			options.ServerAuthorizer{security.AllowEveryone()})
-	}
+func doStartCall(context *context.T, cancel func(), name, method string, opts []rpc.CallOpt, goPtr C.jlong, args []interface{}) (jutil.Object, error) {
 	// Invoke StartCall
-	call, err := (*(*rpc.Client)(jutil.NativePtr(goPtr))).StartCall(ctx, name, method, args, opts...)
+	call, err := (*(*rpc.Client)(jutil.NativePtr(goPtr))).StartCall(context, name, method, args, opts...)
 	if err != nil {
 		return jutil.NullObject, err
 	}
 	env, freeFunc := jutil.GetEnv()
 	defer freeFunc()
-	jContext, err := jcontext.JavaContext(env, ctx, cancel)
+	jContext, err := jcontext.JavaContext(env, context, cancel)
 	if err != nil {
 		return jutil.NullObject, err
 	}
@@ -270,7 +263,7 @@
 }
 
 //export Java_io_v_impl_google_rpc_ClientImpl_nativeStartCall
-func Java_io_v_impl_google_rpc_ClientImpl_nativeStartCall(jenv *C.JNIEnv, jClient C.jobject, goPtr C.jlong, jContext C.jobject, jName C.jstring, jMethod C.jstring, jVomArgs C.jobjectArray, jSkipServerAuth C.jboolean, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_rpc_ClientImpl_nativeStartCall(jenv *C.JNIEnv, jClient C.jobject, goPtr C.jlong, jContext C.jobject, jName C.jstring, jMethod C.jstring, jVomArgs C.jobjectArray, jNameResolutionAuthorizerObj, jServerAuthorizerObj C.jobject, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	name := jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jName))))
 	method := jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jMethod))))
@@ -285,9 +278,27 @@
 		jutil.CallbackOnFailure(env, jCallback, err)
 		return
 	}
-	skipServerAuth := jSkipServerAuth == C.JNI_TRUE
+	var opts []rpc.CallOpt
+	jNameResolutionAuthorizer := jutil.Object(uintptr(unsafe.Pointer(jNameResolutionAuthorizerObj)))
+	if !jNameResolutionAuthorizer.IsNull() {
+		auth, err := jsecurity.GoAuthorizer(env, jNameResolutionAuthorizer)
+		if err != nil {
+			jutil.CallbackOnFailure(env, jCallback, err)
+			return
+		}
+		opts = append(opts, options.NameResolutionAuthorizer{auth})
+	}
+	jServerAuthorizer := jutil.Object(uintptr(unsafe.Pointer(jServerAuthorizerObj)))
+	if !jServerAuthorizer.IsNull() {
+		auth, err := jsecurity.GoAuthorizer(env, jServerAuthorizer)
+		if err != nil {
+			jutil.CallbackOnFailure(env, jCallback, err)
+			return
+		}
+		opts = append(opts, options.ServerAuthorizer{auth})
+	}
 	jutil.DoAsyncCall(env, jCallback, func() (jutil.Object, error) {
-		return doStartCall(ctx, cancel, name, method, skipServerAuth, goPtr, args)
+		return doStartCall(ctx, cancel, name, method, opts, goPtr, args)
 	})
 }
 
diff --git a/v23/security/authorizer.go b/v23/security/authorizer.go
index eb21f2a..15b1b3e 100644
--- a/v23/security/authorizer.go
+++ b/v23/security/authorizer.go
@@ -23,6 +23,13 @@
 	if jAuth.IsNull() {
 		return nil, nil
 	}
+	if jutil.IsInstanceOf(env, jAuth, jPermissionsAuthorizerClass) {
+		ptr, err := jutil.JLongField(env, jAuth, "nativePtr")
+		if err != nil {
+			return nil, err
+		}
+		return *(*security.Authorizer)(jutil.NativePtr(ptr)), nil
+	}
 	// Reference Java dispatcher; it will be de-referenced when the go
 	// dispatcher created below is garbage-collected (through the finalizer
 	// callback we setup below).
diff --git a/v23/security/jni.go b/v23/security/jni.go
index 9bfbf45..b6868e6 100644
--- a/v23/security/jni.go
+++ b/v23/security/jni.go
@@ -63,6 +63,8 @@
 	jDischargeClass jutil.Class
 	// Global reference for io.v.v23.security.DischargeImpetus class.
 	jDischargeImpetusClass jutil.Class
+	// Global reference for io.v.v23.security.access.PermissionsAuthorizer class.
+	jPermissionsAuthorizerClass jutil.Class
 	// Global reference for io.v.v23.uniqueid.Id class.
 	jIdClass jutil.Class
 	// Global reference for java.lang.Object class.
@@ -130,6 +132,10 @@
 	if err != nil {
 		return err
 	}
+	jPermissionsAuthorizerClass, err = jutil.JFindClass(env, "io/v/v23/security/access/PermissionsAuthorizer")
+	if err != nil {
+		return err
+	}
 	jIdClass, err = jutil.JFindClass(env, "io/v/v23/uniqueid/Id")
 	if err != nil {
 		return err
@@ -1042,3 +1048,33 @@
 		jutil.JThrowV(env, err)
 	}
 }
+
+//export Java_io_v_v23_security_VSecurity_nativeCreateAuthorizer
+func Java_io_v_v23_security_VSecurity_nativeCreateAuthorizer(jenv *C.JNIEnv, jVSecurityClass C.jclass, kind C.jint, jKey C.jobject) C.jobject {
+	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
+	var auth security.Authorizer
+	switch kind {
+	case 0:
+		auth = security.AllowEveryone()
+	case 1:
+		auth = security.EndpointAuthorizer()
+	case 2:
+		auth = security.DefaultAuthorizer()
+	case 3:
+		key, err := GoPublicKey(env, jutil.Object(uintptr(unsafe.Pointer(jKey))))
+		if err != nil {
+			jutil.JThrowV(env, err)
+			return nil
+		}
+		auth = security.PublicKeyAuthorizer(key)
+	default:
+		return nil
+	}
+	jutil.GoRef(&auth) // Un-refed when the Java PermissionsAuthorizer is finalized
+	jAuthorizer, err := jutil.NewObject(env, jutil.Class(uintptr(unsafe.Pointer(jPermissionsAuthorizerClass))), []jutil.Sign{jutil.LongSign}, int64(jutil.PtrValue(&auth)))
+	if err != nil {
+		jutil.JThrowV(env, err)
+		return nil
+	}
+	return C.jobject(unsafe.Pointer(jAuthorizer))
+}