/* * * * The MIT License * * * * Copyright {$YEAR} Apothesource, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a copy * * of this software and associated documentation files (the "Software"), to deal * * in the Software without restriction, including without limitation the rights * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * * copies of the Software, and to permit persons to whom the Software is * * furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included in * * all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * * THE SOFTWARE. * */ package com.apothesource.pillfill.service.patient; import com.apothesource.pillfill.datamodel.PFAuthTokenResponse; import com.apothesource.pillfill.datamodel.android.AuthToken; import com.apothesource.pillfill.network.PFNetworkManager; import static com.apothesource.pillfill.utilites.ReactiveUtils.subscribeIoObserveImmediate; import com.apothesource.pillfill.service.PFServiceEndpoints; import com.google.common.io.BaseEncoding; import org.cryptonode.jncryptor.AES256JNCryptor; import org.cryptonode.jncryptor.CryptorException; import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; import javax.crypto.SecretKey; import rx.Observable; import timber.log.Timber; /** * Created by Michael Ramirez on 6/10/15. Copyright 2015, Apothesource, Inc. All Rights Reserved. */ public class PatientLoginService { public Observable<PFAuthTokenResponse> codeLogin(String token) { final String url = String.format(PFServiceEndpoints.CODE_URL, token); Timber.d("CodeLogin", "Accessing url: %s", url); return getAuthTokenResponse(url); } private PFAuthTokenResponse parseAccessTokenResponse(String token) { PFAuthTokenResponse authTokenResponse = PFAuthTokenResponse.parseAuthTokenResponse(token); AuthToken tk = AuthToken.parse(token); assert tk != null; if (authTokenResponse.authToken == null && tk.getEmail() != null) {//Then we've received an authtoken (instead of an authtokenresponse), so create the response authTokenResponse = new PFAuthTokenResponse(); authTokenResponse.success = true; authTokenResponse.errorCode = 200; authTokenResponse.authToken = tk; } return authTokenResponse; } //Create an anonymous account public Observable<PFAuthTokenResponse> anonymousTokenLogin(final LoginStatusListener loginListener) { String url = PFServiceEndpoints.ANONYMOUS_TOKEN_URL; return getAuthTokenResponse(url); } public Observable<PFAuthTokenResponse> pwdLogin(String username, String pwd) { try { String hash = getPwdHash(username, pwd); String url = String.format(PFServiceEndpoints.PWD_LOGIN_URL, username, hash); return getAuthTokenResponse(url); } catch (CryptorException ex) { Logger.getLogger(PatientLoginService.class.getName()).log(Level.SEVERE, null, ex); throw new RuntimeException(ex); } } private Observable<PFAuthTokenResponse> getAuthTokenResponse(String url){ return subscribeIoObserveImmediate(Observable.create(subscriber -> { try { Timber.d("Getting AuthToken for with URL: %s ", url); String pfToken = PFNetworkManager.doPinnedGetForUrl(url); Timber.d("AuthToken response received. Token: %s", pfToken); subscriber.onNext(parseAccessTokenResponse(pfToken)); } catch (Exception e) { Timber.e(e, "Login failed with exception: %s", e.getMessage()); PFAuthTokenResponse response = new PFAuthTokenResponse(); response.exception = e; subscriber.onNext(response); } subscriber.onCompleted(); })); } public static String getPwdHash(String username, char[] password) throws CryptorException { return getPwdHash(username, new String(password)); } public static String getPwdHash(String username, String password) throws CryptorException { AES256JNCryptor jn = new AES256JNCryptor(); char[] concat = (username + password).toCharArray(); byte[] salt = new byte[8]; Arrays.fill(salt, (byte) 0); SecretKey newKey = jn.keyForPassword(concat, salt); //PBKDF2 10K Iterations return BaseEncoding.base64Url().omitPadding().encode(newKey.getEncoded()); } public interface LoginStatusListener { void onLoginComplete(PFAuthTokenResponse authToken); } }