From 967113689da3f98cf4f5ba0ec2f486d32b0b45af Mon Sep 17 00:00:00 2001 From: Steve0x2a Date: Fri, 10 Dec 2021 00:55:27 +0800 Subject: [PATCH] feat: add three idp support by goth. (#351) 1. add 3 providers: apple, azuread(v1) and slack. 2. support importing providers from goth. Signed-off-by: 0x2a --- go.mod | 1 + go.sum | 38 ++++- idp/goth.go | 254 +++++++++++++++++++++++++++++ idp/provider.go | 14 ++ object/user.go | 3 + web/src/ProviderEditPage.js | 3 + web/src/auth/AppleLoginButton.js | 32 ++++ web/src/auth/AzureADLoginButton.js | 32 ++++ web/src/auth/LoginPage.js | 9 + web/src/auth/Provider.js | 20 ++- web/src/auth/SlackLoginButton.js | 32 ++++ 11 files changed, 436 insertions(+), 2 deletions(-) create mode 100644 idp/goth.go create mode 100644 web/src/auth/AppleLoginButton.js create mode 100644 web/src/auth/AzureADLoginButton.js create mode 100644 web/src/auth/SlackLoginButton.js diff --git a/go.mod b/go.mod index 6c6a8a0f..44d552fb 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/golang-jwt/jwt/v4 v4.1.0 github.com/google/uuid v1.2.0 github.com/jinzhu/configor v1.2.1 // indirect + github.com/markbates/goth v1.68.1-0.20211006204042-9dc8905b41c8 github.com/mileusna/crontab v1.0.1 github.com/qiangmzsx/string-adapter/v2 v2.1.0 github.com/qor/oss v0.0.0-20191031055114-aef9ba66bf76 diff --git a/go.sum b/go.sum index 97a81649..b90d3b83 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,8 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.67.0 h1:YIkzmqUfVGiGPpT98L8sVvUIkDno6UlrDxw4NR6z5ak= +cloud.google.com/go v0.67.0/go.mod h1:YNan/mUhNZFrYUor0vqrsQ0Ffl7Xtm/ACOy/vsTS858= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -129,6 +131,8 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= +github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= +github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.1.0 h1:XUgk2Ex5veyVFVeLm0xhusUTQybEbexJXrvPNOKkSY0= github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= @@ -172,8 +176,9 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -184,6 +189,7 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= @@ -192,6 +198,14 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1 h1:LqbZZ9sNMWVjeXS4NN5oVvhMjDyLhmA1LG86oSo+IqY= +github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= @@ -199,6 +213,7 @@ github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= github.com/jinzhu/configor v1.2.1 h1:OKk9dsR8i6HPOCZR8BcMtcEImAFjIhbJFZNyn5GCZko= github.com/jinzhu/configor v1.2.1/go.mod h1:nX89/MOmDba7ZX7GCyU/VIaQ2Ar2aizBl2d3JLF/rDc= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -231,10 +246,16 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ= +github.com/lestrrat-go/jwx v0.9.0 h1:Fnd0EWzTm0kFrBPzE/PEPp9nzllES5buMkksPMjEKpM= +github.com/lestrrat-go/jwx v0.9.0/go.mod h1:iEoxlYfZjvoGpuWwxUz+eR5e6KTJGsaRcy/YNA/UnBk= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/markbates/going v1.0.0 h1:DQw0ZP7NbNlFGcKbcE/IVSOAFzScxRtLpd0rLMzLhq0= +github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA= +github.com/markbates/goth v1.68.1-0.20211006204042-9dc8905b41c8 h1:JibQrkJapVsb0pweJ5T14jZuuYZZTjll0PZBw4XfSCI= +github.com/markbates/goth v1.68.1-0.20211006204042-9dc8905b41c8/go.mod h1:V2VcDMzDiMHW+YmqYl7i0cMiAUeCkAe4QE6jRKBhXZw= github.com/mattermost/xml-roundtrip-validator v0.0.0-20201208211235-fe770d50d911 h1:erppMjjp69Rertg1zlgRbLJH1u+eCmRPxKjMZ5I8/Ro= github.com/mattermost/xml-roundtrip-validator v0.0.0-20201208211235-fe770d50d911/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -251,6 +272,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c h1:3wkDRdxK92dF+c1ke2dtj7ZzemFWBHB9plnJOtlwdFA= +github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -266,6 +289,7 @@ github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHu github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -336,6 +360,7 @@ github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqI github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -412,6 +437,8 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200930145003-4acb6c075d10/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -420,6 +447,7 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 h1:3B43BWw0xEBsLZ/NO1VALz6fppU3481pik+2Ksv45z8= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -462,6 +490,7 @@ golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c= @@ -519,6 +548,8 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -540,6 +571,7 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.32.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -577,6 +609,8 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200929141702-51c3e5b607fe/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -589,6 +623,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/idp/goth.go b/idp/goth.go new file mode 100644 index 00000000..a87b99e1 --- /dev/null +++ b/idp/goth.go @@ -0,0 +1,254 @@ +// Copyright 2021 The casbin Authors. All Rights Reserved. +// +// 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 idp + +import ( + "fmt" + "net/http" + "net/url" + "reflect" + "time" + + "github.com/markbates/goth" + "github.com/markbates/goth/providers/amazon" + "github.com/markbates/goth/providers/apple" + "github.com/markbates/goth/providers/azuread" + "github.com/markbates/goth/providers/bitbucket" + "github.com/markbates/goth/providers/digitalocean" + "github.com/markbates/goth/providers/discord" + "github.com/markbates/goth/providers/dropbox" + "github.com/markbates/goth/providers/facebook" + "github.com/markbates/goth/providers/gitea" + "github.com/markbates/goth/providers/github" + "github.com/markbates/goth/providers/gitlab" + "github.com/markbates/goth/providers/google" + "github.com/markbates/goth/providers/heroku" + "github.com/markbates/goth/providers/instagram" + "github.com/markbates/goth/providers/kakao" + "github.com/markbates/goth/providers/line" + "github.com/markbates/goth/providers/linkedin" + "github.com/markbates/goth/providers/microsoftonline" + "github.com/markbates/goth/providers/paypal" + "github.com/markbates/goth/providers/salesforce" + "github.com/markbates/goth/providers/shopify" + "github.com/markbates/goth/providers/slack" + "github.com/markbates/goth/providers/tumblr" + "github.com/markbates/goth/providers/twitter" + "github.com/markbates/goth/providers/yahoo" + "github.com/markbates/goth/providers/yandex" + "github.com/markbates/goth/providers/zoom" + "golang.org/x/oauth2" +) + +type GothIdProvider struct { + Provider goth.Provider + Session goth.Session +} + +func NewGothIdProvider(providerType string, clientId string, clientSecret string, redirectUrl string) *GothIdProvider { + var idp GothIdProvider + switch providerType { + case "Amazon": + idp = GothIdProvider{ + Provider: amazon.New(clientId, clientSecret, redirectUrl), + Session: &amazon.Session{}, + } + case "Apple": + idp = GothIdProvider{ + Provider: apple.New(clientId, clientSecret, redirectUrl, nil), + Session: &apple.Session{}, + } + case "AzureAD": + idp = GothIdProvider{ + Provider: azuread.New(clientId, clientSecret, redirectUrl, nil), + Session: &azuread.Session{}, + } + case "Bitbucket": + idp = GothIdProvider{ + Provider: bitbucket.New(clientId, clientSecret, redirectUrl), + Session: &bitbucket.Session{}, + } + case "DigitalOcean": + idp = GothIdProvider{ + Provider: digitalocean.New(clientId, clientSecret, redirectUrl), + Session: &digitalocean.Session{}, + } + case "Discord": + idp = GothIdProvider{ + Provider: discord.New(clientId, clientSecret, redirectUrl), + Session: &discord.Session{}, + } + case "Dropbox": + idp = GothIdProvider{ + Provider: dropbox.New(clientId, clientSecret, redirectUrl), + Session: &dropbox.Session{}, + } + case "Facebook": + idp = GothIdProvider{ + Provider: facebook.New(clientId, clientSecret, redirectUrl), + Session: &facebook.Session{}, + } + case "Gitea": + idp = GothIdProvider{ + Provider: gitea.New(clientId, clientSecret, redirectUrl), + Session: &gitea.Session{}, + } + case "GitHub": + idp = GothIdProvider{ + Provider: github.New(clientId, clientSecret, redirectUrl), + Session: &github.Session{}, + } + case "GitLab": + idp = GothIdProvider{ + Provider: gitlab.New(clientId, clientSecret, redirectUrl), + Session: &gitlab.Session{}, + } + case "Google": + idp = GothIdProvider{ + Provider: google.New(clientId, clientSecret, redirectUrl), + Session: &google.Session{}, + } + case "Heroku": + idp = GothIdProvider{ + Provider: heroku.New(clientId, clientSecret, redirectUrl), + Session: &heroku.Session{}, + } + case "Instagram": + idp = GothIdProvider{ + Provider: instagram.New(clientId, clientSecret, redirectUrl), + Session: &instagram.Session{}, + } + case "Kakao": + idp = GothIdProvider{ + Provider: kakao.New(clientId, clientSecret, redirectUrl), + Session: &kakao.Session{}, + } + case "Linkedin": + idp = GothIdProvider{ + Provider: linkedin.New(clientId, clientSecret, redirectUrl), + Session: &linkedin.Session{}, + } + case "Line": + idp = GothIdProvider{ + Provider: line.New(clientId, clientSecret, redirectUrl), + Session: &line.Session{}, + } + case "MicrosoftOnline": + idp = GothIdProvider{ + Provider: microsoftonline.New(clientId, clientSecret, redirectUrl), + Session: µsoftonline.Session{}, + } + case "Paypal": + idp = GothIdProvider{ + Provider: paypal.New(clientId, clientSecret, redirectUrl), + Session: &paypal.Session{}, + } + case "SalesForce": + idp = GothIdProvider{ + Provider: salesforce.New(clientId, clientSecret, redirectUrl), + Session: &salesforce.Session{}, + } + case "Shopify": + idp = GothIdProvider{ + Provider: shopify.New(clientId, clientSecret, redirectUrl), + Session: &shopify.Session{}, + } + case "Slack": + idp = GothIdProvider{ + Provider: slack.New(clientId, clientSecret, redirectUrl), + Session: &slack.Session{}, + } + case "Tumblr": + idp = GothIdProvider{ + Provider: tumblr.New(clientId, clientSecret, redirectUrl), + Session: &tumblr.Session{}, + } + case "Twitter": + idp = GothIdProvider{ + Provider: twitter.New(clientId, clientSecret, redirectUrl), + Session: &twitter.Session{}, + } + case "Yahoo": + idp = GothIdProvider{ + Provider: yahoo.New(clientId, clientSecret, redirectUrl), + Session: &yahoo.Session{}, + } + case "Yandex": + idp = GothIdProvider{ + Provider: yandex.New(clientId, clientSecret, redirectUrl), + Session: &yandex.Session{}, + } + case "Zoom": + idp = GothIdProvider{ + Provider: zoom.New(clientId, clientSecret, redirectUrl), + Session: &zoom.Session{}, + } + } + + return &idp +} + +//Goth's idp all implement the Client method, but since the goth.Provider interface does not provide to modify idp's client method, reflection is required +func (idp *GothIdProvider) SetHttpClient(client *http.Client) { + idpClient := reflect.ValueOf(idp.Provider).Elem().FieldByName("HTTPClient") + idpClient.Set(reflect.ValueOf(client)) +} + +func (idp *GothIdProvider) GetToken(code string) (*oauth2.Token, error) { + var expireAt time.Time + //Need to construct variables supported by goth + //to call the function to obtain accessToken + value := url.Values{} + value.Add("code", code) + accessToken, err := idp.Session.Authorize(idp.Provider, value) + //Get ExpiresAt's value + valueOfExpire := reflect.ValueOf(idp.Session).Elem().FieldByName("ExpiresAt") + if valueOfExpire.IsValid() { + expireAt = valueOfExpire.Interface().(time.Time) + } + token := oauth2.Token{ + AccessToken: accessToken, + Expiry: expireAt, + } + return &token, err +} + +func (idp *GothIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) { + gothUser, err := idp.Provider.FetchUser(idp.Session) + if err != nil { + return nil, err + } + return getUser(gothUser), nil +} + +func getUser(gothUser goth.User) *UserInfo { + user := UserInfo{ + Id: gothUser.UserID, + Username: gothUser.Name, + DisplayName: gothUser.NickName, + Email: gothUser.Email, + AvatarUrl: gothUser.AvatarURL, + } + //Some idp return an empty Name + //so construct the Name with firstname and lastname or nickname + if user.Username == "" { + user.Username = fmt.Sprintf("%v%v", gothUser.FirstName, gothUser.LastName) + } + if user.Username == "" { + user.Username = gothUser.NickName + } + + return &user +} diff --git a/idp/provider.go b/idp/provider.go index 10a3ee08..747e3808 100644 --- a/idp/provider.go +++ b/idp/provider.go @@ -16,6 +16,7 @@ package idp import ( "net/http" + "strings" "golang.org/x/oauth2" ) @@ -59,7 +60,20 @@ func GetIdProvider(providerType string, clientId string, clientSecret string, re return NewLarkIdProvider(clientId, clientSecret, redirectUrl) } else if providerType == "GitLab" { return NewGitlabIdProvider(clientId, clientSecret, redirectUrl) + } else if isGothSupport(providerType) { + return NewGothIdProvider(providerType, clientId, clientSecret, redirectUrl) } return nil } + +var gothList = []string{"Apple", "AzureAd", "Slack"} + +func isGothSupport(provider string) bool { + for _, value := range gothList { + if strings.EqualFold(value, provider) { + return true + } + } + return false +} diff --git a/object/user.go b/object/user.go index c4e9d6fd..2fd10dbe 100644 --- a/object/user.go +++ b/object/user.go @@ -78,6 +78,9 @@ type User struct { Wecom string `xorm:"wecom varchar(100)" json:"wecom"` Lark string `xorm:"lark varchar(100)" json:"lark"` Gitlab string `xorm:"gitlab varchar(100)" json:"gitlab"` + Apple string `xorm:"apple varchar(100)" json:"apple"` + AzureAD string `xorm:"azuread varchar(100)" json:"azuread"` + Slack string `xorm:"slack varchar(100)" json:"slack"` Ldap string `xorm:"ldap varchar(100)" json:"ldap"` Properties map[string]string `json:"properties"` diff --git a/web/src/ProviderEditPage.js b/web/src/ProviderEditPage.js index bee94683..5eeb0cb8 100644 --- a/web/src/ProviderEditPage.js +++ b/web/src/ProviderEditPage.js @@ -80,6 +80,9 @@ class ProviderEditPage extends React.Component { {id: 'WeCom', name: 'WeCom'}, {id: 'Lark', name: 'Lark'}, {id: 'GitLab', name: 'GitLab'}, + {id: 'Apple', name: 'Apple'}, + {id: 'AzureAD', name: 'AzureAD'}, + {id: 'Slack', name: 'Slack'}, ] ); } else if (provider.category === "Email") { diff --git a/web/src/auth/AppleLoginButton.js b/web/src/auth/AppleLoginButton.js new file mode 100644 index 00000000..97cf216e --- /dev/null +++ b/web/src/auth/AppleLoginButton.js @@ -0,0 +1,32 @@ +// Copyright 2021 The casbin Authors. All Rights Reserved. +// +// 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. + +import {createButton} from "react-social-login-buttons"; +import {StaticBaseUrl} from "../Setting"; + +function Icon({ width = 24, height = 24, color }) { + return Sign in with Apple; +} + +const config = { + text: "Sign in with Apple", + icon: Icon, + iconFormat: name => `fa fa-${name}`, + style: {background: "#ffffff", color: "#000000"}, + activeStyle: {background: "#ededee"}, +}; + +const AppleLoginButton = createButton(config); + +export default AppleLoginButton; diff --git a/web/src/auth/AzureADLoginButton.js b/web/src/auth/AzureADLoginButton.js new file mode 100644 index 00000000..d626fb61 --- /dev/null +++ b/web/src/auth/AzureADLoginButton.js @@ -0,0 +1,32 @@ +// Copyright 2021 The casbin Authors. All Rights Reserved. +// +// 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. + +import {createButton} from "react-social-login-buttons"; +import {StaticBaseUrl} from "../Setting"; + +function Icon({ width = 24, height = 24, color }) { + return Sign in with AzureAD; +} + +const config = { + text: "Sign in with AzureAD", + icon: Icon, + iconFormat: name => `fa fa-${name}`, + style: {background: "#ffffff", color: "#000000"}, + activeStyle: {background: "#ededee"}, +}; + +const AzureADLoginButton = createButton(config); + +export default AzureADLoginButton; diff --git a/web/src/auth/LoginPage.js b/web/src/auth/LoginPage.js index d2e207e1..4ffaa0ab 100644 --- a/web/src/auth/LoginPage.js +++ b/web/src/auth/LoginPage.js @@ -34,6 +34,9 @@ import LinkedInLoginButton from "./LinkedInLoginButton"; import WeComLoginButton from "./WeComLoginButton"; import LarkLoginButton from "./LarkLoginButton"; import GitLabLoginButton from "./GitLabLoginButton"; +import AppleLoginButton from "./AppleLoginButton" +import AzureADLoginButton from "./AzureADLoginButton"; +import SlackLoginButton from "./SlackLoginButton"; import CustomGithubCorner from "../CustomGithubCorner"; import {CountDownInput} from "../component/CountDownInput"; @@ -180,6 +183,12 @@ class LoginPage extends React.Component { return } else if (type === "GitLab") { return + } else if (type === "Apple") { + return + } else if (type === "AzureAD") { + return + } else if (type === "Slack") { + return } return text; diff --git a/web/src/auth/Provider.js b/web/src/auth/Provider.js index cd50a410..dc24223f 100644 --- a/web/src/auth/Provider.js +++ b/web/src/auth/Provider.js @@ -67,6 +67,18 @@ const authInfo = { scope: "read_user+profile", endpoint: "https://gitlab.com/oauth/authorize", }, + Apple: { + scope: "name%20email", + endpoint: "https://appleid.apple.com/auth/authorize", + }, + AzureAD: { + scope: "user_impersonation", + endpoint: "https://login.microsoftonline.com/common/oauth2/authorize", + }, + Slack: { + scope: "users:read", + endpoint: "https://slack.com/oauth/authorize", + }, }; const otherProviderInfo = { @@ -205,5 +217,11 @@ export function getAuthUrl(application, provider, method) { return `${endpoint}?app_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}`; } else if (provider.type === "GitLab") { return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}`; - } + } else if (provider.type === "Apple") { + return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&response_mode=form_post`; + } else if (provider.type === "AzureAD") { + return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&resource=https://graph.windows.net/`; + } else if (provider.type === "Slack") { + return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}`; + } } diff --git a/web/src/auth/SlackLoginButton.js b/web/src/auth/SlackLoginButton.js new file mode 100644 index 00000000..a9409f76 --- /dev/null +++ b/web/src/auth/SlackLoginButton.js @@ -0,0 +1,32 @@ +// Copyright 2021 The casbin Authors. All Rights Reserved. +// +// 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. + +import {createButton} from "react-social-login-buttons"; +import {StaticBaseUrl} from "../Setting"; + +function Icon({ width = 24, height = 24, color }) { + return Sign in with Slack; +} + +const config = { + text: "Sign in with Slack", + icon: Icon, + iconFormat: name => `fa fa-${name}`, + style: {background: "#ffffff", color: "#000000"}, + activeStyle: {background: "#ededee"}, +}; + +const SlackLoginButton = createButton(config); + +export default SlackLoginButton;