Add sshauthentication-api v1 support

This commit is contained in:
Christian Hagau
2017-10-05 00:00:00 +00:00
parent 83ab483fc7
commit 2619cb1db3
57 changed files with 3954 additions and 79 deletions

View File

@@ -0,0 +1,36 @@
apply plugin: 'com.android.library'
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
// NOTE: Do not place application dependencies here
}
}
android {
if (project.hasProperty('rootProject.ext.compileSdkVersion')) {
compileSdkVersion rootProject.ext.compileSdkVersion
} else {
compileSdkVersion 25
}
if (project.hasProperty('rootProject.ext.buildToolsVersion')) {
buildToolsVersion rootProject.ext.buildToolsVersion
} else {
buildToolsVersion '25.0.2'
}
defaultConfig {
minSdkVersion 9
targetSdkVersion 25
versionCode 1
versionName "1.0"
}
// Do not abort build if lint finds errors
lintOptions {
abortOnError false
}
}

View File

@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.openintents.ssh.authentication">
<application/>
</manifest>

View File

@@ -0,0 +1,6 @@
// ISshAuthenticationService.aidl
package org.openintents.ssh.authentication;
interface ISshAuthenticationService {
Intent execute(in Intent intent);
}

View File

@@ -0,0 +1,219 @@
/*
* Copyright (C) 2017 Christian Hagau <ach@hagau.se>
* Copyright (C) 2017 Michael Perk
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.ssh.authentication;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Build;
import android.util.Log;
public class SshAuthenticationApi {
private static final String TAG = "SshAuthenticationApi";
public static final String SERVICE_INTENT = "org.openintents.ssh.authentication.ISshAuthenticationService";
public static final String EXTRA_API_VERSION = "api_version";
public static final int API_VERSION = 1;
public static final String EXTRA_RESULT_CODE = "result_code";
public static final int RESULT_CODE_ERROR = 0;
public static final int RESULT_CODE_SUCCESS = 1;
public static final int RESULT_CODE_USER_INTERACTION_REQUIRED = 2;
/**
* ACTION_SIGN
*
* Sign a given challenge
*
* required extras:
* String EXTRA_KEY_ID
* byte[] EXTRA_CHALLENGE
* int EXTRA_HASH_ALGORITHM
*
* returned extras:
* byte[] EXTRA_SIGNATURE
*/
public static final String ACTION_SIGN = "org.openintents.ssh.action.SIGN";
public static final String EXTRA_CHALLENGE = "challenge";
public static final String EXTRA_HASH_ALGORITHM = "hash_algorithm";
public static final String EXTRA_SIGNATURE = "signature";
/* hash algorithms used in signature generation */
public static final int SHA1 = 0;
public static final int SHA224 = 1;
public static final int SHA256 = 2;
public static final int SHA384 = 3;
public static final int SHA512 = 4;
public static final int RIPEMD160 = 5;
/**
* ACTION_SELECT_KEY
*
* Select a key
*
* returned extras:
* String EXTRA_KEY_ID
* String EXTRA_KEY_DESCRIPTION
*/
public static final String ACTION_SELECT_KEY = "org.openintents.ssh.action.SELECT_KEY";
public static final String EXTRA_KEY_DESCRIPTION = "key_description";
/**
* ACTION_GET_PUBLIC_KEY
*
* Get the public key for a key
*
* returns the public key encoded according to the ASN.1 type
* 'SubjectPublicKeyInfo' as defined in the X.509 standard,
* see RFC5280, RFC3279 and draft-ietf-curdle-pkix
* and their respective updates
*
* required extras:
* String EXTRA_KEY_ID
*
* returned extras:
* byte[] EXTRA_PUBLIC_KEY
* int EXTRA_PUBLIC_KEY_ALGORITHM
*/
public static final String ACTION_GET_PUBLIC_KEY = "org.openintents.ssh.action.GET_PUBLIC_KEY";
public static final String EXTRA_PUBLIC_KEY = "public_key";
public static final String EXTRA_PUBLIC_KEY_ALGORITHM = "public_key_algorithm";
/* public key algorithms */
public static final int RSA = 0;
public static final int ECDSA = 1;
public static final int EDDSA = 2;
public static final int DSA = 3;
/**
* ACTION_GET_SSH_PUBLIC_KEY
*
* Get the SSH public key for a key
*
* returns the public key in SSH public key format,
* as described in RFC4253, RFC5656 and draft-ietf-curdle-ssh-ed25519
* and their respective updates
*
* required extras:
* String EXTRA_KEY_ID
*
* returned extras:
* String EXTRA_SSH_PUBLIC_KEY
*/
public static final String ACTION_GET_SSH_PUBLIC_KEY = "org.openintents.ssh.action.GET_SSH_PUBLIC_KEY";
public static final String EXTRA_SSH_PUBLIC_KEY = "ssh_public_key";
/**
* Error result of type SshAuthenticationApiError
*/
public static final String EXTRA_ERROR = "error";
/**
* Pending Intent requiring user interaction
*/
public static final String EXTRA_PENDING_INTENT = "intent";
/**
* Key identifier
*/
public static final String EXTRA_KEY_ID = "key_id";
private final ISshAuthenticationService mService;
private final Context mContext;
public SshAuthenticationApi(Context context, ISshAuthenticationService service) {
mService = service;
mContext = context;
}
public interface ISshAgentCallback {
void onReturn(final Intent result);
}
private class SshAgentAsyncTask extends AsyncTask<Void, Integer, Intent> {
Intent data;
ISshAgentCallback callback;
private SshAgentAsyncTask(Intent data, ISshAgentCallback callback) {
this.data = data;
this.callback = callback;
}
@Override
protected Intent doInBackground(Void... unused) {
return executeApi(data);
}
protected void onPostExecute(Intent result) {
callback.onReturn(result);
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void executeApiAsync(Intent data, ISshAgentCallback callback) {
SshAgentAsyncTask task = new SshAgentAsyncTask(data, callback);
// don't serialize async tasks, always execute them in parallel
// http://commonsware.com/blog/2012/04/20/asynctask-threading-regression-confirmed.html
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
} else {
task.execute((Void[]) null);
}
}
public Intent executeApi(Intent data) {
try {
// always send version from client
data.putExtra(SshAuthenticationApi.EXTRA_API_VERSION, SshAuthenticationApi.API_VERSION);
Intent result;
// blocks until result is ready
result = mService.execute(data);
// set class loader to current context to allow unparcelling of SshAuthenticationApiError
// http://stackoverflow.com/a/3806769
result.setExtrasClassLoader(mContext.getClassLoader());
return result;
} catch (Exception e) {
Log.e(TAG, "Exception in executeApi call", e);
return createExceptionErrorResult(SshAuthenticationApiError.CLIENT_SIDE_ERROR,
"Exception in executeApi call", e);
}
}
private Intent createErrorResult(int errorCode, String errorMessage) {
Log.e(TAG, errorMessage);
Intent result = new Intent();
result.putExtra(SshAuthenticationApi.EXTRA_ERROR, new SshAuthenticationApiError(errorCode, errorMessage));
result.putExtra(SshAuthenticationApi.EXTRA_RESULT_CODE, SshAuthenticationApi.RESULT_CODE_ERROR);
return result;
}
private Intent createExceptionErrorResult(int errorCode, String errorMessage, Exception e) {
String message = errorMessage + " : " + e.getMessage();
return createErrorResult(errorCode, message);
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2017 Christian Hagau <ach@hagau.se>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.ssh.authentication;
import android.os.Parcel;
import android.os.Parcelable;
public class SshAuthenticationApiError implements Parcelable {
/**
* Error codes
*/
/* values chosen for compatibility with openpgp-api */
public static final int CLIENT_SIDE_ERROR = -1;
public static final int GENERIC_ERROR = 0;
public static final int INCOMPATIBLE_API_VERSIONS = 1;
public static final int INTERNAL_ERROR = 2;
/* values chosen for no intersection with openpgp-api */
public static final int UNKNOWN_ACTION = -128;
public static final int NO_KEY_ID = -129;
public static final int NO_SUCH_KEY = -130;
public static final int NO_AUTH_KEY = -131;
/* values chosen to be invalid enumeration values in their respective domain */
public static final int INVALID_ALGORITHM = -254;
public static final int INVALID_HASH_ALGORITHM = -253;
private int mError;
private String mMessage;
public SshAuthenticationApiError(int error, String message) {
mError = error;
mMessage = message;
}
protected SshAuthenticationApiError(Parcel in) {
mError = in.readInt();
mMessage = in.readString();
}
public static final Creator<SshAuthenticationApiError> CREATOR = new Creator<SshAuthenticationApiError>() {
@Override
public SshAuthenticationApiError createFromParcel(Parcel in) {
return new SshAuthenticationApiError(in);
}
@Override
public SshAuthenticationApiError[] newArray(int size) {
return new SshAuthenticationApiError[size];
}
};
public int getError() {
return mError;
}
public String getMessage() {
return mMessage;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mError);
dest.writeString(mMessage);
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2017 Christian Hagau <ach@hagau.se>
* Copyright (C) 2017 Jonas Dippel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.ssh.authentication;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
public class SshAuthenticationConnection {
private final Context mContext;
private final String mTargetPackage;
private ISshAuthenticationService mSSHAgent;
/**
* Callback for signaling connection events
*/
public interface OnBound {
/**
* Called when the connection is bound to the service
*
* @param sshAgent the bound remote service stub
*/
void onBound(ISshAuthenticationService sshAgent);
/**
* Called when the connection is disconnected due to some error
*/
void onError();
}
private OnBound mOnBoundListener;
/**
* Construct an SshAuthenticationConnection instance with the desired attributes
*
* @param context the application context
* @param targetPackage the package of the service to bind to
*/
public SshAuthenticationConnection(Context context, String targetPackage) {
mContext = context;
mTargetPackage = targetPackage;
}
private final ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mSSHAgent = ISshAuthenticationService.Stub.asInterface(service);
mOnBoundListener.onBound(mSSHAgent);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mSSHAgent = null;
mOnBoundListener.onError();
}
};
/**
* Connect to the Service via a Connection
*
* @return false if service was not found or an error occured, else true
*/
public boolean connect(final OnBound onBoundListener) {
mOnBoundListener = onBoundListener;
if (mSSHAgent == null) {
Intent intent = new Intent(SshAuthenticationApi.SERVICE_INTENT);
intent.setPackage(mTargetPackage);
return mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
} else {
mOnBoundListener.onBound(mSSHAgent);
return true;
}
}
/**
* Check whether the Connection is bound to a service
*
* @return whether the Connection is bound to a service
*/
public boolean isConnected() {
return mSSHAgent != null;
}
public void disconnect() {
mSSHAgent = null;
mContext.unbindService(mServiceConnection);
}
public ISshAuthenticationService getService() {
return mSSHAgent;
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2017 Christian Hagau <ach@hagau.se>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.ssh.authentication.request;
import android.content.Intent;
import org.openintents.ssh.authentication.SshAuthenticationApi;
public class KeySelectionRequest extends Request {
@Override
protected void getData(Intent intent) {
}
@Override
protected void putData(Intent request) {
}
@Override
protected String getAction() {
return SshAuthenticationApi.ACTION_SELECT_KEY;
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2017 Christian Hagau <ach@hagau.se>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.ssh.authentication.request;
import android.content.Intent;
import org.openintents.ssh.authentication.SshAuthenticationApi;
public class PublicKeyRequest extends Request {
private String mKeyId;
public PublicKeyRequest(String keyId) {
mKeyId = keyId;
}
@Override
protected void getData(Intent intent) {
mKeyId = intent.getStringExtra(SshAuthenticationApi.EXTRA_KEY_ID);
}
@Override
protected void putData(Intent request) {
request.putExtra(SshAuthenticationApi.EXTRA_KEY_ID, mKeyId);
}
@Override
protected String getAction() {
return SshAuthenticationApi.ACTION_GET_PUBLIC_KEY;
}
public String getKeyID() {
return mKeyId;
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2017 Christian Hagau <ach@hagau.se>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.ssh.authentication.request;
import android.content.Intent;
public abstract class Request {
public Intent toIntent() {
Intent request = new Intent();
request.setAction(getAction());
putData(request);
return request;
}
private void populatefromIntent(Intent intent) {
getData(intent);
}
protected abstract void getData(Intent intent);
protected abstract void putData(Intent request);
protected abstract String getAction();
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2017 Christian Hagau <ach@hagau.se>
* Copyright (C) 2017 Michael Perk
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.ssh.authentication.request;
import android.content.Intent;
import org.openintents.ssh.authentication.SshAuthenticationApi;
import org.openintents.ssh.authentication.SshAuthenticationApiError;
public class SigningRequest extends Request {
private byte[] mChallenge;
private String mKeyIdentifier;
private int mHashAlgorithm;
public SigningRequest(byte[] challenge, String keyIdentifier, int hashAlgorithm) {
mHashAlgorithm = hashAlgorithm;
mKeyIdentifier = keyIdentifier;
mChallenge = challenge;
}
@Override
protected String getAction() {
return SshAuthenticationApi.ACTION_SIGN;
}
@Override
protected void getData(Intent intent) {
mHashAlgorithm = intent.getIntExtra(SshAuthenticationApi.EXTRA_HASH_ALGORITHM, SshAuthenticationApiError.INVALID_HASH_ALGORITHM);
mKeyIdentifier = intent.getStringExtra(SshAuthenticationApi.EXTRA_KEY_ID);
mChallenge = intent.getByteArrayExtra(SshAuthenticationApi.EXTRA_CHALLENGE);
}
@Override
protected void putData(Intent request) {
request.putExtra(SshAuthenticationApi.EXTRA_HASH_ALGORITHM, mHashAlgorithm);
request.putExtra(SshAuthenticationApi.EXTRA_KEY_ID, mKeyIdentifier);
request.putExtra(SshAuthenticationApi.EXTRA_CHALLENGE, mChallenge);
}
public int getHashAlgorithm() {
return mHashAlgorithm;
}
public String getKeyIdentifier() {
return mKeyIdentifier;
}
public byte[] getChallenge() {
return mChallenge;
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2017 Christian Hagau <ach@hagau.se>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.ssh.authentication.request;
import android.content.Intent;
import org.openintents.ssh.authentication.SshAuthenticationApi;
public class SshPublicKeyRequest extends Request {
private String mKeyId;
public SshPublicKeyRequest(String keyId) {
mKeyId = keyId;
}
@Override
protected void getData(Intent intent) {
mKeyId = intent.getStringExtra(SshAuthenticationApi.EXTRA_KEY_ID);
}
@Override
protected void putData(Intent request) {
request.putExtra(SshAuthenticationApi.EXTRA_KEY_ID, mKeyId);
}
@Override
protected String getAction() {
return SshAuthenticationApi.ACTION_GET_SSH_PUBLIC_KEY;
}
public String getKeyId() {
return mKeyId;
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2017 Christian Hagau <ach@hagau.se>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.ssh.authentication.response;
import android.app.PendingIntent;
import android.content.Intent;
import org.openintents.ssh.authentication.SshAuthenticationApi;
import org.openintents.ssh.authentication.SshAuthenticationApiError;
public class KeySelectionResponse extends Response {
private String mKeyId;
private String mKeyDescription;
public KeySelectionResponse(Intent data) {
super(data);
}
public KeySelectionResponse(PendingIntent pendingIntent) {
super(pendingIntent);
}
public KeySelectionResponse(SshAuthenticationApiError error) {
super(error);
}
public KeySelectionResponse(String keyId, String keyDescription) {
super();
mKeyId = keyId;
mKeyDescription = keyDescription;
}
@Override
protected void getResults(Intent intent) {
mKeyId = intent.getStringExtra(SshAuthenticationApi.EXTRA_KEY_ID);
mKeyDescription = intent.getStringExtra(SshAuthenticationApi.EXTRA_KEY_DESCRIPTION);
}
@Override
protected void putResults(Intent intent) {
intent.putExtra(SshAuthenticationApi.EXTRA_KEY_ID, mKeyId);
intent.putExtra(SshAuthenticationApi.EXTRA_KEY_DESCRIPTION, mKeyDescription);
}
public String getKeyId() {
return mKeyId;
}
public String getKeyDescription() {
return mKeyDescription;
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) 2017 Christian Hagau <ach@hagau.se>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.ssh.authentication.response;
import android.app.PendingIntent;
import android.content.Intent;
import org.openintents.ssh.authentication.SshAuthenticationApi;
import org.openintents.ssh.authentication.SshAuthenticationApiError;
public class PublicKeyResponse extends Response {
public static final int INVALID_ALGORITHM = SshAuthenticationApiError.INVALID_ALGORITHM;
private byte[] mEncodedPublicKey;
private int mKeyAlgorithm;
public PublicKeyResponse(Intent data) {
super(data);
}
public PublicKeyResponse(PendingIntent pendingIntent) {
super(pendingIntent);
}
public PublicKeyResponse(SshAuthenticationApiError error) {
super(error);
}
public PublicKeyResponse(byte[] encodedPublicKey,
int keyAlgorithm) {
super();
mEncodedPublicKey = encodedPublicKey;
mKeyAlgorithm = keyAlgorithm;
}
@Override
protected void getResults(Intent intent) {
mEncodedPublicKey = intent.getByteArrayExtra(SshAuthenticationApi.EXTRA_PUBLIC_KEY);
mKeyAlgorithm = intent.getIntExtra(SshAuthenticationApi.EXTRA_PUBLIC_KEY_ALGORITHM, INVALID_ALGORITHM);
}
@Override
protected void putResults(Intent intent) {
intent.putExtra(SshAuthenticationApi.EXTRA_PUBLIC_KEY, mEncodedPublicKey);
intent.putExtra(SshAuthenticationApi.EXTRA_PUBLIC_KEY_ALGORITHM, mKeyAlgorithm);
}
public byte[] getEncodedPublicKey() {
return mEncodedPublicKey;
}
public int getKeyAlgorithm() {
return mKeyAlgorithm;
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2017 Christian Hagau <ach@hagau.se>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.ssh.authentication.response;
import android.app.PendingIntent;
import android.content.Intent;
import org.openintents.ssh.authentication.SshAuthenticationApi;
import org.openintents.ssh.authentication.SshAuthenticationApiError;
public abstract class Response {
public static final int RESULT_CODE_ERROR = SshAuthenticationApi.RESULT_CODE_ERROR;
public static final int RESULT_CODE_SUCCESS = SshAuthenticationApi.RESULT_CODE_SUCCESS;
public static final int RESULT_CODE_USER_INTERACTION_REQUIRED = SshAuthenticationApi.RESULT_CODE_USER_INTERACTION_REQUIRED;
protected int mResultCode;
protected PendingIntent mPendingIntent;
protected SshAuthenticationApiError mError;
protected Response() {
mResultCode = RESULT_CODE_SUCCESS;
}
public Response(Intent data) {
populateFromIntent(data);
}
public Response(PendingIntent pendingIntent) {
mPendingIntent = pendingIntent;
mResultCode = RESULT_CODE_USER_INTERACTION_REQUIRED;
}
public Response(SshAuthenticationApiError error) {
mError = error;
mResultCode = RESULT_CODE_ERROR;
}
private void populateFromIntent(Intent intent) {
int resultCode = intent.getIntExtra(SshAuthenticationApi.EXTRA_RESULT_CODE, SshAuthenticationApi.RESULT_CODE_ERROR);
switch (resultCode) {
case SshAuthenticationApi.RESULT_CODE_SUCCESS:
mResultCode = RESULT_CODE_SUCCESS;
getResults(intent);
break;
case SshAuthenticationApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
mResultCode = RESULT_CODE_USER_INTERACTION_REQUIRED;
mPendingIntent = intent.getParcelableExtra(SshAuthenticationApi.EXTRA_PENDING_INTENT);
break;
case SshAuthenticationApi.RESULT_CODE_ERROR:
mResultCode = RESULT_CODE_ERROR;
mError = intent.getParcelableExtra(SshAuthenticationApi.EXTRA_ERROR);
}
}
public Intent toIntent() {
Intent intent = new Intent();
switch (mResultCode) {
case RESULT_CODE_SUCCESS:
intent.putExtra(SshAuthenticationApi.EXTRA_RESULT_CODE, SshAuthenticationApi.RESULT_CODE_SUCCESS);
putResults(intent);
break;
case RESULT_CODE_USER_INTERACTION_REQUIRED:
intent.putExtra(SshAuthenticationApi.EXTRA_RESULT_CODE, SshAuthenticationApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
intent.putExtra(SshAuthenticationApi.EXTRA_PENDING_INTENT, mPendingIntent);
break;
case RESULT_CODE_ERROR:
intent.putExtra(SshAuthenticationApi.EXTRA_RESULT_CODE, SshAuthenticationApi.RESULT_CODE_ERROR);
intent.putExtra(SshAuthenticationApi.EXTRA_ERROR, mError);
}
return intent;
}
public int getResultCode() {
return mResultCode;
}
public PendingIntent getPendingIntent() {
return mPendingIntent;
}
public SshAuthenticationApiError getError() {
return mError;
}
protected abstract void getResults(Intent intent);
protected abstract void putResults(Intent intent);
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2017 Christian Hagau <ach@hagau.se>
* Copyright (C) 2017 Jonas Dippel, Michael Perk
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.ssh.authentication.response;
import android.app.PendingIntent;
import android.content.Intent;
import org.openintents.ssh.authentication.SshAuthenticationApi;
import org.openintents.ssh.authentication.SshAuthenticationApiError;
public class SigningResponse extends Response {
private byte[] mSignature;
public SigningResponse(Intent data) {
super(data);
}
public SigningResponse(PendingIntent pendingIntent) {
super(pendingIntent);
}
public SigningResponse(SshAuthenticationApiError error) {
super(error);
}
public SigningResponse(byte[] signature) {
super();
mSignature = signature;
}
@Override
protected void getResults(Intent intent) {
mSignature = intent.getByteArrayExtra(SshAuthenticationApi.EXTRA_SIGNATURE);
}
@Override
protected void putResults(Intent intent) {
intent.putExtra(SshAuthenticationApi.EXTRA_SIGNATURE, mSignature);
}
public byte[] getSignature() {
return mSignature;
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2017 Christian Hagau <ach@hagau.se>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.ssh.authentication.response;
import android.app.PendingIntent;
import android.content.Intent;
import org.openintents.ssh.authentication.SshAuthenticationApi;
import org.openintents.ssh.authentication.SshAuthenticationApiError;
public class SshPublicKeyResponse extends Response {
private String mSshPublicKey;
public SshPublicKeyResponse(Intent data) {
super(data);
}
public SshPublicKeyResponse(PendingIntent pendingIntent) {
super(pendingIntent);
}
public SshPublicKeyResponse(SshAuthenticationApiError error) {
super(error);
}
public SshPublicKeyResponse(String sshPublicKey) {
super();
mSshPublicKey = sshPublicKey;
}
@Override
protected void getResults(Intent intent) {
mSshPublicKey = intent.getStringExtra(SshAuthenticationApi.EXTRA_SSH_PUBLIC_KEY);
}
@Override
protected void putResults(Intent intent) {
intent.putExtra(SshAuthenticationApi.EXTRA_SSH_PUBLIC_KEY, mSshPublicKey);
}
public String getSshPublicKey() {
return mSshPublicKey;
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2017 Christian Hagau <ach@hagau.se>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.ssh.authentication.util;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import org.openintents.ssh.authentication.SshAuthenticationApi;
import java.util.ArrayList;
import java.util.List;
public class SshAuthenticationApiUtils {
public static List<String> getAgentProviders(Context context) {
Intent intent = new Intent(SshAuthenticationApi.SERVICE_INTENT);
List<ResolveInfo> resolvedInfo = context.getPackageManager().queryIntentServices(intent, 0);
ArrayList<String> providers = new ArrayList<>();
if (resolvedInfo != null) {
for (ResolveInfo resolveInfoEntry : resolvedInfo) {
providers.add(resolveInfoEntry.serviceInfo.packageName);
}
}
return providers;
}
}