public void TestParsePersonaAssertion() { try { Log.D(Database.TAG, "testParsePersonaAssertion"); var sampleAssertion = "eyJhbGciOiJSUzI1NiJ9.eyJwdWJsaWMta2V5Ijp7ImFsZ29yaXRobSI6IkRTIiwieSI6ImNhNWJiYTYzZmI4MDQ2OGE0MjFjZjgxYTIzN2VlMDcwYTJlOTM4NTY0ODhiYTYzNTM0ZTU4NzJjZjllMGUwMDk0ZWQ2NDBlOGNhYmEwMjNkYjc5ODU3YjkxMzBlZGNmZGZiNmJiNTUwMWNjNTk3MTI1Y2NiMWQ1ZWQzOTVjZTMyNThlYjEwN2FjZTM1ODRiOWIwN2I4MWU5MDQ4NzhhYzBhMjFlOWZkYmRjYzNhNzNjOTg3MDAwYjk4YWUwMmZmMDQ4ODFiZDNiOTBmNzllYzVlNDU1YzliZjM3NzFkYjEzMTcxYjNkMTA2ZjM1ZDQyZmZmZjQ2ZWZiZDcwNjgyNWQiLCJwIjoiZmY2MDA0ODNkYjZhYmZjNWI0NWVhYjc4NTk0YjM1MzNkNTUwZDlmMWJmMmE5OTJhN2E4ZGFhNmRjMzRmODA0NWFkNGU2ZTBjNDI5ZDMzNGVlZWFhZWZkN2UyM2Q0ODEwYmUwMGU0Y2MxNDkyY2JhMzI1YmE4MWZmMmQ1YTViMzA1YThkMTdlYjNiZjRhMDZhMzQ5ZDM5MmUwMGQzMjk3NDRhNTE3OTM4MDM0NGU4MmExOGM0NzkzMzQzOGY4OTFlMjJhZWVmODEyZDY5YzhmNzVlMzI2Y2I3MGVhMDAwYzNmNzc2ZGZkYmQ2MDQ2MzhjMmVmNzE3ZmMyNmQwMmUxNyIsInEiOiJlMjFlMDRmOTExZDFlZDc5OTEwMDhlY2FhYjNiZjc3NTk4NDMwOWMzIiwiZyI6ImM1MmE0YTBmZjNiN2U2MWZkZjE4NjdjZTg0MTM4MzY5YTYxNTRmNGFmYTkyOTY2ZTNjODI3ZTI1Y2ZhNmNmNTA4YjkwZTVkZTQxOWUxMzM3ZTA3YTJlOWUyYTNjZDVkZWE3MDRkMTc1ZjhlYmY2YWYzOTdkNjllMTEwYjk2YWZiMTdjN2EwMzI1OTMyOWU0ODI5YjBkMDNiYmM3ODk2YjE1YjRhZGU1M2UxMzA4NThjYzM0ZDk2MjY5YWE4OTA0MWY0MDkxMzZjNzI0MmEzODg5NWM5ZDViY2NhZDRmMzg5YWYxZDdhNGJkMTM5OGJkMDcyZGZmYTg5NjIzMzM5N2EifSwicHJpbmNpcGFsIjp7ImVtYWlsIjoiamVuc0Btb29zZXlhcmQuY29tIn0sImlhdCI6MTM1ODI5NjIzNzU3NywiZXhwIjoxMzU4MzgyNjM3NTc3LCJpc3MiOiJsb2dpbi5wZXJzb25hLm9yZyJ9.RnDK118nqL2wzpLCVRzw1MI4IThgeWpul9jPl6ypyyxRMMTurlJbjFfs-BXoPaOem878G8-4D2eGWS6wd307k7xlPysevYPogfFWxK_eDHwkTq3Ts91qEDqrdV_JtgULC8c1LvX65E0TwW_GL_TM94g3CvqoQnGVxxoaMVye4ggvR7eOZjimWMzUuu4Lo9Z-VBHBj7XM0UMBie57CpGwH4_Wkv0V_LHZRRHKdnl9ISp_aGwfBObTcHG9v0P3BW9vRrCjihIn0SqOJQ9obl52rMf84GD4Lcy9NIktzfyka70xR9Sh7ALotW7rWywsTzMTu3t8AzMz2MJgGjvQmx49QA~eyJhbGciOiJEUzEyOCJ9.eyJleHAiOjEzNTgyOTY0Mzg0OTUsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6NDk4NC8ifQ.4FV2TrUQffDya0MOxOQlzJQbDNvCPF2sfTIJN7KOLvvlSFPknuIo5g"; var result = PersonaAuthorizer.ParseAssertion(sampleAssertion); var email = (string)result.Get(PersonaAuthorizer.AssertionFieldEmail); var origin = (string)result.Get(PersonaAuthorizer.AssertionFieldOrigin); Assert.AreEqual(email, "*****@*****.**"); Assert.AreEqual(origin, "http://localhost:4984/"); Assert.AreEqual(PersonaAuthorizer.RegisterAssertion(sampleAssertion), email); Uri originURL = new Uri(origin); var gotAssertion = PersonaAuthorizer.AssertionForEmailAndSite(email, originURL); Assert.AreEqual(gotAssertion, sampleAssertion); // variant form of URL originURL = new Uri("Http://LocalHost:4984/"); gotAssertion = PersonaAuthorizer.AssertionForEmailAndSite(email, originURL); Assert.AreEqual(sampleAssertion, gotAssertion); var auth = new PersonaAuthorizer(email); Assert.AreEqual(email, auth.GetEmailAddress()); Assert.AreEqual(null, auth.AssertionForSite(originURL)); } catch (Exception e) { Assert.Fail(e.Message); } }
/// <summary> /// Verifies and registers a persona token for use in replication authentication /// </summary> /// <returns>The response state for further HTTP processing</returns> /// <param name="context">The context of the Couchbase Lite HTTP request</param> public static ICouchbaseResponseState RegisterPersonaToken(ICouchbaseListenerContext context) { var response = context.CreateResponse(); var body = context.BodyAs <Dictionary <string, object> >(); string email = PersonaAuthorizer.RegisterAssertion(body.GetCast <string>("assertion")); if (email != null) { response.JsonBody = new Body(new Dictionary <string, object> { { "ok", "registered" }, { "email", email } }); } else { response.InternalStatus = StatusCode.BadParam; response.JsonBody = new Body(new Dictionary <string, object> { { "error", "invalid assertion" } }); } return(response.AsDefaultState()); }
private Status ParseReplicationProperties(IDictionary <string, object> properties, out bool isPush, out bool createTarget, IDictionary <string, object> results) { // http://wiki.apache.org/couchdb/Replication isPush = false; createTarget = false; var sourceDict = ParseSourceOrTarget(properties, "source"); var targetDict = ParseSourceOrTarget(properties, "target"); var source = sourceDict.GetCast <string>("url"); var target = targetDict.GetCast <string>("url"); if (source == null || target == null) { return(new Status(StatusCode.BadRequest)); } createTarget = properties.GetCast <bool>("create_target", false); IDictionary <string, object> remoteDict = null; bool targetIsLocal = Manager.IsValidDatabaseName(target); if (Manager.IsValidDatabaseName(source)) { //Push replication if (targetIsLocal) { // This is a local-to-local replication. It is not supported on .NET. return(new Status(StatusCode.NotImplemented)); } remoteDict = targetDict; if (results.ContainsKey("database")) { results["database"] = GetExistingDatabase(source); } isPush = true; } else if (targetIsLocal) { //Pull replication remoteDict = sourceDict; if (results.ContainsKey("database")) { Database db; if (createTarget) { db = GetDatabase(target); if (db == null) { return(new Status(StatusCode.DbError)); } } else { db = GetExistingDatabase(target); } results["database"] = db; } } else { return(new Status(StatusCode.BadId)); } Uri remote; if (!Uri.TryCreate(remoteDict.GetCast <string>("url"), UriKind.Absolute, out remote)) { Log.To.Router.W(TAG, "Unparseable replication URL <{0}> received", remoteDict.GetCast <string>("url")); return(new Status(StatusCode.BadRequest)); } if (!remote.Scheme.Equals("http") && !remote.Scheme.Equals("https") && !remote.Scheme.Equals("ws") && !remote.Scheme.Equals("wss")) { Log.To.Router.W(TAG, "Replication URL <{0}> has unsupported scheme", remote); return(new Status(StatusCode.BadRequest)); } var split = remote.PathAndQuery.Split('?'); if (split.Length != 1) { Log.To.Router.W(TAG, "Replication URL <{0}> must not contain a query", remote); return(new Status(StatusCode.BadRequest)); } var path = split[0]; if (String.IsNullOrEmpty(path) || path == "/") { Log.To.Router.W(TAG, "Replication URL <{0}> missing database name", remote); return(new Status(StatusCode.BadRequest)); } var database = results.Get("database"); if (database == null) { return(new Status(StatusCode.NotFound)); } if (results.ContainsKey("remote")) { results["remote"] = remote; } if (results.ContainsKey("headers")) { results["headers"] = remoteDict.Get("headers") ?? new Dictionary <string, string>(); } if (results.ContainsKey("authorizer")) { var auth = remoteDict.Get("auth") as IDictionary <string, object>; if (auth != null) { var persona = auth.Get("persona") as IDictionary <string, object>; var facebook = auth.Get("facebook") as IDictionary <string, object>; if (persona != null) { string email = persona.Get("email") as string; results["authorizer"] = new PersonaAuthorizer(email); } else if (facebook != null) { string email = facebook.Get("email") as string; results["authorizer"] = new FacebookAuthorizer(email); } else { Log.To.Sync.W(TAG, "Invalid authorizer settings {0}", new SecureLogJsonString(auth, LogMessageSensitivity.Insecure)); } } } // Can't specify both a filter and doc IDs if (properties.ContainsKey("filter") && properties.ContainsKey("doc_ids")) { return(new Status(StatusCode.BadRequest)); } return(new Status(StatusCode.Ok)); }
private Status ParseReplicationProperties(IDictionary <string, object> properties, out bool isPush, out bool createTarget, IDictionary <string, object> results) { // http://wiki.apache.org/couchdb/Replication isPush = false; createTarget = false; var sourceDict = ParseSourceOrTarget(properties, "source"); var targetDict = ParseSourceOrTarget(properties, "target"); var source = sourceDict.Get("url") as string; var target = targetDict.Get("url") as string; if (source == null || target == null) { return(new Status(StatusCode.BadRequest)); } createTarget = properties.Get("create_target") is bool && (bool)properties.Get("create_target"); IDictionary <string, object> remoteDict = null; bool targetIsLocal = Manager.IsValidDatabaseName(target); if (Manager.IsValidDatabaseName(source)) { //Push replication if (targetIsLocal) { // This is a local-to-local replication. Turn the remote into a full URL to keep the // replicator happy: Database targetDb; if (createTarget) { targetDb = Manager.SharedInstance.GetDatabase(target); } else { targetDb = Manager.SharedInstance.GetExistingDatabase(target); } if (targetDb == null) { return(new Status(StatusCode.BadRequest)); } targetDict["url"] = "http://localhost:20000" + targetDb.Path; } remoteDict = targetDict; if (results.ContainsKey("database")) { results["database"] = GetExistingDatabase(source); } isPush = true; } else if (targetIsLocal) { //Pull replication remoteDict = sourceDict; if (results.ContainsKey("database")) { Database db; if (createTarget) { db = GetDatabase(target); if (db == null) { return(new Status(StatusCode.DbError)); } } else { db = GetExistingDatabase(target); } results["database"] = db; } } else { return(new Status(StatusCode.BadId)); } Uri remote = new Uri(remoteDict["url"] as string); if (!remote.Scheme.Equals("http") && !remote.Scheme.Equals("https") && !remote.Scheme.Equals("cbl")) { return(new Status(StatusCode.BadRequest)); } var database = results.Get("database"); if (database == null) { return(new Status(StatusCode.NotFound)); } if (results.ContainsKey("remote")) { results["remote"] = remote; } if (results.ContainsKey("headers")) { results["headers"] = remoteDict.Get("headers"); } if (results.ContainsKey("authorizer")) { var auth = remoteDict.Get("auth") as IDictionary <string, object>; if (auth != null) { //var oauth = auth["oauth"] as IDictionary<string, object>; var persona = auth.Get("persona") as IDictionary <string, object>; var facebook = auth.Get("facebook") as IDictionary <string, object>; //TODO: OAuth /*if (oauth != null) { * string consumerKey = oauth.Get("consumer_key") as string; * string consumerSec = oauth.Get("consumer_secret") as string; * string token = oauth.Get("token") as string; * string tokenSec = oauth.Get("token_secret") as string; * string sigMethod = oauth.Get("signature_method") as string; * results["authorizer"] = * }*/ if (persona != null) { string email = persona.Get("email") as string; results["authorizer"] = new PersonaAuthorizer(email); } else if (facebook != null) { string email = facebook.Get("email") as string; results["authorizer"] = new FacebookAuthorizer(email); } else { Log.W(TAG, "Invalid authorizer settings {0}", auth); } } } // Can't specify both a filter and doc IDs if (properties.ContainsKey("filter") && properties.ContainsKey("doc_ids")) { return(new Status(StatusCode.BadRequest)); } return(new Status(StatusCode.Ok)); }
public virtual Replication GetReplicator(IDictionary <string, object> properties) { // TODO: in the iOS equivalent of this code, there is: {@"doc_ids", _documentIDs}) - write unit test that detects this bug // TODO: ditto for "headers" Authorizer authorizer = null; Replication repl = null; Uri remote = null; IDictionary <string, object> remoteMap; IDictionary <string, object> sourceMap = ParseSourceOrTarget(properties, "source"); IDictionary <string, object> targetMap = ParseSourceOrTarget(properties, "target"); string source = (string)sourceMap.Get("url"); string target = (string)targetMap.Get("url"); bool createTargetBoolean = (bool)properties.Get("create_target"); bool createTarget = (createTargetBoolean != null && createTargetBoolean); bool continuousBoolean = (bool)properties.Get("continuous"); bool continuous = (continuousBoolean != null && continuousBoolean); bool cancelBoolean = (bool)properties.Get("cancel"); bool cancel = (cancelBoolean != null && cancelBoolean); // Map the 'source' and 'target' JSON params to a local database and remote URL: if (source == null || target == null) { throw new CouchbaseLiteException("source and target are both null", new Status(Status .BadRequest)); } bool push = false; Database db = null; string remoteStr = null; if (Couchbase.Lite.Manager.IsValidDatabaseName(source)) { db = GetExistingDatabase(source); remoteStr = target; push = true; remoteMap = targetMap; } else { remoteStr = source; if (createTarget && !cancel) { bool mustExist = false; db = GetDatabaseWithoutOpening(target, mustExist); if (!db.Open()) { throw new CouchbaseLiteException("cannot open database: " + db, new Status(Status .InternalServerError)); } } else { db = GetExistingDatabase(target); } if (db == null) { throw new CouchbaseLiteException("database is null", new Status(Status.NotFound)); } remoteMap = sourceMap; } IDictionary <string, object> authMap = (IDictionary <string, object>)remoteMap.Get( "auth"); if (authMap != null) { IDictionary <string, object> persona = (IDictionary <string, object>)authMap.Get("persona" ); if (persona != null) { string email = (string)persona.Get("email"); authorizer = new PersonaAuthorizer(email); } IDictionary <string, object> facebook = (IDictionary <string, object>)authMap.Get("facebook" ); if (facebook != null) { string email = (string)facebook.Get("email"); authorizer = new FacebookAuthorizer(email); } } try { remote = new Uri(remoteStr); } catch (UriFormatException) { throw new CouchbaseLiteException("malformed remote url: " + remoteStr, new Status (Status.BadRequest)); } if (remote == null || !remote.Scheme.StartsWith("http")) { throw new CouchbaseLiteException("remote URL is null or non-http: " + remoteStr, new Status(Status.BadRequest)); } if (!cancel) { repl = db.GetReplicator(remote, GetDefaultHttpClientFactory(), push, continuous, GetWorkExecutor()); if (repl == null) { throw new CouchbaseLiteException("unable to create replicator with remote: " + remote , new Status(Status.InternalServerError)); } if (authorizer != null) { repl.SetAuthorizer(authorizer); } string filterName = (string)properties.Get("filter"); if (filterName != null) { repl.SetFilter(filterName); IDictionary <string, object> filterParams = (IDictionary <string, object>)properties .Get("query_params"); if (filterParams != null) { repl.SetFilterParams(filterParams); } } if (push) { ((Pusher)repl).SetCreateTarget(createTarget); } } else { // Cancel replication: repl = db.GetActiveReplicator(remote, push); if (repl == null) { throw new CouchbaseLiteException("unable to lookup replicator with remote: " + remote , new Status(Status.NotFound)); } } return(repl); }
/// <summary>Private Constructor</summary> protected Replication(Database db, Uri remote, bool continuous, IHttpClientFactory clientFactory, TaskFactory workExecutor, CancellationTokenSource tokenSource = null) { LocalDatabase = db; Continuous = continuous; WorkExecutor = workExecutor; CancellationTokenSource = tokenSource ?? new CancellationTokenSource(); RemoteUrl = remote; Status = ReplicationStatus.Stopped; online = true; RequestHeaders = new Dictionary <String, Object>(); if (RemoteUrl.GetQuery() != null && !RemoteUrl.GetQuery().IsEmpty()) { var uri = new Uri(remote.ToString()); var personaAssertion = URIUtils.GetQueryParameter(uri, PersonaAuthorizer.QueryParameter); if (personaAssertion != null && !personaAssertion.IsEmpty()) { var email = PersonaAuthorizer.RegisterAssertion(personaAssertion); var authorizer = new PersonaAuthorizer(email); Authorizer = authorizer; } var facebookAccessToken = URIUtils.GetQueryParameter(uri, FacebookAuthorizer.QueryParameter); if (facebookAccessToken != null && !facebookAccessToken.IsEmpty()) { var email = URIUtils.GetQueryParameter(uri, FacebookAuthorizer.QueryParameterEmail); var authorizer = new FacebookAuthorizer(email); Uri remoteWithQueryRemoved = null; try { remoteWithQueryRemoved = new UriBuilder(remote.Scheme, remote.GetHost(), remote.Port, remote.AbsolutePath).Uri; } catch (UriFormatException e) { throw new ArgumentException("Invalid URI format.", "remote", e); } FacebookAuthorizer.RegisterAccessToken(facebookAccessToken, email, remoteWithQueryRemoved.ToString()); Authorizer = authorizer; } // we need to remove the query from the URL, since it will cause problems when // communicating with sync gw / couchdb try { RemoteUrl = new UriBuilder(remote.Scheme, remote.GetHost(), remote.Port, remote.AbsolutePath).Uri; } catch (UriFormatException e) { throw new ArgumentException("Invalid URI format.", "remote", e); } } Batcher = new Batcher <RevisionInternal>(workExecutor, InboxCapacity, ProcessorDelay, inbox => { Log.V(Database.Tag, "*** " + this + ": BEGIN processInbox (" + inbox.Count + " sequences)"); ProcessInbox(new RevisionList(inbox)); Log.V(Database.Tag, "*** " + this.ToString() + ": END processInbox (lastSequence=" + LastSequence); UpdateActive(); }, CancellationTokenSource); this.clientFactory = clientFactory ?? CouchbaseLiteHttpClientFactory.Instance; }