diff --git a/go-dockerfile b/Dockerfile similarity index 100% rename from go-dockerfile rename to Dockerfile diff --git a/README.md b/README.md index a18433f3..2dd125c1 100644 --- a/README.md +++ b/README.md @@ -1,146 +1,131 @@ Casdoor ==== +[![Go Report Card](https://goreportcard.com/badge/github.com/casbin/casdoor)](https://goreportcard.com/report/github.com/casbin/casdoor) license [![GitHub issues](https://img.shields.io/github/issues/casbin/casdoor?style=flat-square)](https://github.com/casbin/casdoor/issues) [![GitHub stars](https://img.shields.io/github/stars/casbin/casdoor?style=flat-square)](https://github.com/casbin/casdoor/stargazers) [![GitHub forks](https://img.shields.io/github/forks/casbin/casdoor?style=flat-square)](https://github.com/casbin/casdoor/network) + Casdoor is a UI-first centralized authentication / Single-Sign-On (SSO) platform based on OAuth 2.0 / OIDC. ## Online demo -### Casdoor +Deployed site: https://door.casbin.com/ -Casdoor is the authentication server. It serves both the web UI and the login requests from the application users. +## Quick Start -- Deployed site: https://door.casbin.com/ -- Source code: https://github.com/casbin/casdoor (this repo) +Run your own casdoor program in a few minutes:smiley: -Global admin login: +### Download -- Username: `admin` -- Password: `123` +There are two methods, get code via go subcommand `get`: -### Web application +```shell +go get github.com/casbin/casdoor +``` -Casbin-OA is one of our applications that use Casdoor as authentication. + or `git`: -- Deployed site: https://oa.casbin.com/ -- Source code: https://github.com/casbin/casbin-oa +```bash +git clone https://github.com/casbin/casdoor +``` -## Architecture +Finally, change directory: -Casdoor contains 2 parts: +```bash +cd casdoor/ +``` -Name | Description | Language | Source code -----|------|----|---- -Frontend | Web frontend UI for Casdoor | Javascript + React | https://github.com/casbin/casdoor/tree/master/web -Backend | RESTful API backend for Casdoor | Golang + Beego + MySQL | https://github.com/casbin/casdoor +We provide two start up methods for all kinds of users. -## Installation +### Manual -- Get code via `go get`: +#### Simple configuration - ```shell - go get github.com/casbin/casdoor - ``` +Edit `conf/app.conf`, modify `dataSourceName` to correct database info, which follows this format: - or `git clone`: +```bash +username:password@tcp(database_ip:database_port)/ +``` - ```shell - git clone https://github.com/casbin/casdoor - ``` +#### Run -## Run through Docker -- Install Docker and Docker-compose,you see [docker](https://docs.docker.com/get-docker/) and [docker-compose](https://docs.docker.com/compose/install/) -- vi casdoor/conf/app.conf -- Modify dataSourceName = root:123@tcp(localhost:3306)/ to dataSourceName = root:123@tcp(db:3306)/ -- Execute the following command - ```shell - docker-compose up - ``` -- Open browser: +Casdoor provides two run modes, the difference is binary size and user prompt. - http://localhost:8000/ +##### Dev Mode -## Run (Dev Environment) +Edit `conf/app.conf`, set `runmode=dev`. Firstly build front-end files: -- Run backend (in port 8000): +```bash +cd web/ && npm install && npm run start +``` - ```shell - go run main.go - ``` +Then build back-end binary file, change directory to root(Relative to casdoor): -- Run frontend (in the same machine's port 7001): +```bash +go run main.go +``` - ```shell - cd web - ## npm - npm install - npm run start - ## yarn - yarn install - yarn run start - ``` +That's it! Try to visit http://127.0.0.1:7001/. :small_airplane: -- Open browser: +##### Prod Mode - http://localhost:7001/ +Edit `conf/app.conf`, set `runmode=prod`. Firstly build front-end files: -## Run (Production Environment) +```bash +cd web/ && npm install && npm run build +``` -- build static pages: +Then build back-end binary file, change directory to root(Relative to casdoor): - ``` - cd web - ## npm - npm run build - ## yarn - yarn run build - ## back to casdoor directory - cd .. - ``` +```bash +go build main.go && sudo ./main +``` -- build and run go code: +> Notice, you should visit back-end port, default 8000. Now try to visit http://127.0.0.1:8000/ - ``` - go build - ./casdoor - ``` +### Docker -Now, Casdoor is running on port 8000. You can access Casdoor pages directly in your browser, or you can setup a reverse proxy to hold your domain name, SSL, etc. +This method requires [docker](https://docs.docker.com/get-docker/) and [docker-compose](https://docs.docker.com/compose/install/) to be installed first. -## Config +#### Simple configuration -- Setup database (MySQL): +Edit `conf/app.conf`, modify `dataSourceName` to the fixed content: - Casdoor will store its users, nodes and topics informations in a MySQL database named: `casdoor`, will create it if not existed. The DB connection string can be specified at: https://github.com/casbin/casdoor/blob/master/conf/app.conf +```bash +dataSourceName = root:123@tcp(db:3306)/ +``` - ```ini - db = mysql - dataSourceName = root:123@tcp(localhost:3306)/ - dbName = casdoor - ``` +> If you need to modify `conf/app.conf`, you need to re-run `docker-compose up`. -- Setup database (Postgres): +#### Run - Since we must choose a database when opening Postgres with xorm, you should prepare a database manually before running Casdoor. Let's assume that you have already prepared a database called `casdoor`, then you should specify `app.conf` like this: +Just execute: - ``` ini - db = postgres - dataSourceName = "user=postgres password=xxx sslmode=disable dbname=" - dbName = casdoor - ``` +```bash +docker-compose up +``` - **Please notice:** You can add Postgres parameters in `dataSourceName`, but please make sure that `dataSourceName` ends with `dbname=`. Or database adapter may crash when you launch Casdoor. +That's - Casdoor uses XORM to connect to DB, so all DBs supported by XORM can also be used. +## Detailed documentation -- Github corner +We also provide a complete [document](https://casdoor.org/) as a reference. - We added a Github icon in the upper right corner, linking to your Github repository address. - You could set `ShowGithubCorner` to hidden it. +## Other examples - Configuration (`web/src/commo/Conf.js`): +These all use casdoor as a centralized authentication platform. - ```javascript - export const ShowGithubCorner = true +- [Casnode](https://github.com/casbin/casnode): Next-generation forum software based on React + Golang. +- [Casbin-OA](https://github.com/casbin/casbin-oa): A full-featured OA(Office Assistant) system. +- ...... + +## Contribute + +For casdoor, if you have any questions, you can give Issues, and you can also directly Pull Requests(but we recommend give issues first to communicate with the community). + +In addition to contributing codes to casdoor, uou can also contribute to the [internationalization of casdoor](https://crowdin.com/project/casdoor-web) by translating for casdoor in the language you are good at. + +Both are welcome! :kissing_smiling_eyes: + +## License + + [Apache-2.0](https://github.com/casbin/casdoor/blob/master/LICENSE) - export const GithubRepo = "https://github.com/casbin/casdoor" //your github repository - ``` diff --git a/controllers/account.go b/controllers/account.go index 7584b8cb..488f9c5e 100644 --- a/controllers/account.go +++ b/controllers/account.go @@ -72,6 +72,7 @@ type HumanCheck struct { CaptchaImage interface{} `json:"captchaImage"` } +// Signup // @Title Signup // @Description sign up a new user // @Param username formData string true "The username to sign up" @@ -178,6 +179,7 @@ func (c *ApiController) Signup() { c.ServeJSON() } +// Logout // @Title Logout // @Description logout the current user // @Success 200 {object} controllers.Response The Response object @@ -197,6 +199,7 @@ func (c *ApiController) Logout() { c.ServeJSON() } +// GetAccount // @Title GetAccount // @Description get the details of the current account // @Success 200 {object} controllers.Response The Response object @@ -224,6 +227,7 @@ func (c *ApiController) GetAccount() { c.ServeJSON() } +// UploadAvatar // @Title UploadAvatar // @Description upload avatar // @Param avatarfile formData string true "The base64 encode of avatarfile" @@ -272,6 +276,7 @@ func (c *ApiController) UploadAvatar() { c.ServeJSON() } +// GetHumanCheck ... func (c *ApiController) GetHumanCheck() { c.Data["json"] = HumanCheck{Type: "none"} diff --git a/controllers/application.go b/controllers/application.go index 59930de3..150e7729 100644 --- a/controllers/application.go +++ b/controllers/application.go @@ -20,6 +20,7 @@ import ( "github.com/casbin/casdoor/object" ) +// GetApplications // @Title GetApplications // @Description get all applications // @Param owner query string true "The owner of applications." @@ -32,6 +33,7 @@ func (c *ApiController) GetApplications() { c.ServeJSON() } +// GetApplication // @Title GetApplication // @Description get the detail of an application // @Param id query string true "The id of the application." @@ -44,6 +46,7 @@ func (c *ApiController) GetApplication() { c.ServeJSON() } +// GetUserApplication // @Title GetUserApplication // @Description get the detail of the user's application // @Param id query string true "The id of the user" @@ -61,6 +64,7 @@ func (c *ApiController) GetUserApplication() { c.ServeJSON() } +// UpdateApplication // @Title UpdateApplication // @Description update an application // @Param id query string true "The id of the application" @@ -80,6 +84,7 @@ func (c *ApiController) UpdateApplication() { c.ServeJSON() } +// AddApplication // @Title AddApplication // @Description add an application // @Param body body object.Application true "The details of the application" @@ -96,6 +101,7 @@ func (c *ApiController) AddApplication() { c.ServeJSON() } +// DeleteApplication // @Title DeleteApplication // @Description delete an application // @Param body body object.Application true "The details of the application" diff --git a/controllers/auth.go b/controllers/auth.go index 50f479ad..3d349be3 100644 --- a/controllers/auth.go +++ b/controllers/auth.go @@ -30,14 +30,14 @@ import ( func codeToResponse(code *object.Code) *Response { if code.Code == "" { return &Response{Status: "error", Msg: code.Message, Data: code.Code} - } else { - return &Response{Status: "ok", Msg: "", Data: code.Code} } + + return &Response{Status: "ok", Msg: "", Data: code.Code} } -func (c *ApiController) HandleLoggedIn(application *object.Application, user *object.User, form *RequestForm) *Response { +// HandleLoggedIn ... +func (c *ApiController) HandleLoggedIn(application *object.Application, user *object.User, form *RequestForm) (resp *Response) { userId := user.GetId() - resp := &Response{} if form.Type == ResponseTypeLogin { c.SetSessionUsername(userId) util.LogInfo(c.Ctx, "API: [%s] signed in", userId) @@ -72,6 +72,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob return resp } +// GetApplicationLogin ... // @Title GetApplicationLogin // @Description get application login // @Param clientId query string true "client id" @@ -108,6 +109,7 @@ func setHttpClient(idProvider idp.IdProvider, providerType string) { } } +// Login ... // @Title Login // @Description login // @Param oAuthParams query string true "oAuth parameters" @@ -182,13 +184,11 @@ func (c *ApiController) Login() { c.ResponseError("wrong email!") } object.DisableVerificationCode(form.Email) - break case "phone": if user.Phone != form.Email { c.ResponseError("wrong phone!") } object.DisableVerificationCode(form.Email) - break } } else { password := form.Password @@ -282,7 +282,7 @@ func (c *ApiController) Login() { record.Organization = application.Organization record.Username = user.Name - object.AddRecord(record) + object.AddRecord(record) } else { // Sign up via OAuth if !application.EnableSignUp { diff --git a/controllers/base.go b/controllers/base.go index 3649b8ba..6b80535a 100644 --- a/controllers/base.go +++ b/controllers/base.go @@ -29,6 +29,7 @@ type SessionData struct { ExpireTime int64 } +// GetSessionUsername ... func (c *ApiController) GetSessionUsername() string { // check if user session expired sessionData := c.GetSessionData() @@ -48,10 +49,12 @@ func (c *ApiController) GetSessionUsername() string { return user.(string) } +// SetSessionUsername ... func (c *ApiController) SetSessionUsername(user string) { c.SetSession("username", user) } +// GetSessionData ... func (c *ApiController) GetSessionData() *SessionData { session := c.GetSession("SessionData") if session == nil { @@ -67,6 +70,7 @@ func (c *ApiController) GetSessionData() *SessionData { return sessionData } +// SetSessionData ... func (c *ApiController) SetSessionData(s *SessionData) { if s == nil { c.DelSession("SessionData") diff --git a/controllers/ldap.go b/controllers/ldap.go index d9a28827..a2e083b5 100644 --- a/controllers/ldap.go +++ b/controllers/ldap.go @@ -97,7 +97,6 @@ func (c *ApiController) GetLdapUser() { c.Data["json"] = Response{Status: "ok", Data: resp} c.ServeJSON() - return } func (c *ApiController) GetLdaps() { diff --git a/controllers/link.go b/controllers/link.go index d96f1b41..4c98917b 100644 --- a/controllers/link.go +++ b/controllers/link.go @@ -24,6 +24,7 @@ type LinkForm struct { ProviderType string `json:"providerType"` } +// Unlink ... func (c *ApiController) Unlink() { userId, ok := c.RequireSignedIn() if !ok { diff --git a/controllers/organization.go b/controllers/organization.go index 2d5389c4..78c4092d 100644 --- a/controllers/organization.go +++ b/controllers/organization.go @@ -20,6 +20,7 @@ import ( "github.com/casbin/casdoor/object" ) +// GetOrganizations ... // @Title GetOrganizations // @Description get organizations // @Param owner query string true "owner" @@ -32,6 +33,7 @@ func (c *ApiController) GetOrganizations() { c.ServeJSON() } +// GetOrganization ... // @Title GetOrganization // @Description get organization // @Param id query string true "organization id" @@ -44,6 +46,7 @@ func (c *ApiController) GetOrganization() { c.ServeJSON() } +// UpdateOrganization ... // @Title UpdateOrganization // @Description update organization // @Param id query string true "The id of the organization" @@ -63,6 +66,7 @@ func (c *ApiController) UpdateOrganization() { c.ServeJSON() } +// AddOrganization ... // @Title AddOrganization // @Description add organization // @Param body body object.Organization true "The details of the organization" @@ -79,6 +83,7 @@ func (c *ApiController) AddOrganization() { c.ServeJSON() } +// DeleteOrganization ... // @Title DeleteOrganization // @Description delete organization // @Param body body object.Organization true "The details of the organization" diff --git a/controllers/provider.go b/controllers/provider.go index fbf7a707..fbd3afcb 100644 --- a/controllers/provider.go +++ b/controllers/provider.go @@ -20,6 +20,7 @@ import ( "github.com/casbin/casdoor/object" ) +// GetProviders // @Title GetProviders // @Description get providers // @Param owner query string true "The owner of providers" diff --git a/controllers/record.go b/controllers/record.go index 0e4f8f6b..e91610b6 100644 --- a/controllers/record.go +++ b/controllers/record.go @@ -20,6 +20,7 @@ import ( "github.com/casbin/casdoor/object" ) +// GetRecords // @Title GetRecords // @Description get all records // @Success 200 {array} object.Records The Response object @@ -29,6 +30,7 @@ func (c *ApiController) GetRecords() { c.ServeJSON() } +// GetRecordsByFilter // @Title GetRecordsByFilter // @Description get records by filter // @Param body body object.Records true "filter Record message" diff --git a/controllers/service.go b/controllers/service.go index 40823864..7125d4ec 100644 --- a/controllers/service.go +++ b/controllers/service.go @@ -25,6 +25,7 @@ import ( sender "github.com/casdoor/go-sms-sender" ) +// SendEmail // @Title SendEmail // @Description This API is not for Casdoor frontend to call, it is for Casdoor SDKs. // @Param clientId query string true "The clientId of the application" @@ -84,8 +85,7 @@ func (c *ApiController) SendEmail() { emailForm.Title, emailForm.Content, receiver, - emailForm.Sender); - len(msg) == 0 { + emailForm.Sender); len(msg) == 0 { ok++ } } @@ -94,6 +94,7 @@ func (c *ApiController) SendEmail() { c.ServeJSON() } +// SendSms // @Title SendSms // @Description This API is not for Casdoor frontend to call, it is for Casdoor SDKs. // @Param clientId query string true "The clientId of the application" @@ -148,7 +149,7 @@ func (c *ApiController) SendSms() { } } - if len(invalidReceivers) != 0{ + if len(invalidReceivers) != 0 { c.ResponseError("Invalid phone numbers", invalidReceivers) return } diff --git a/controllers/token.go b/controllers/token.go index dac2543e..c128fcec 100644 --- a/controllers/token.go +++ b/controllers/token.go @@ -20,6 +20,7 @@ import ( "github.com/casbin/casdoor/object" ) +// GetTokens // @Title GetTokens // @Description get tokens // @Param owner query string true "The owner of tokens" @@ -32,6 +33,7 @@ func (c *ApiController) GetTokens() { c.ServeJSON() } +// GetToken // @Title GetToken // @Description get token // @Param id query string true "The id of token" @@ -44,6 +46,7 @@ func (c *ApiController) GetToken() { c.ServeJSON() } +// UpdateToken // @Title UpdateToken // @Description update token // @Param id query string true "The id of token" @@ -63,6 +66,7 @@ func (c *ApiController) UpdateToken() { c.ServeJSON() } +// AddToken // @Title AddToken // @Description add token // @Param body body object.Token true "Details of the token" @@ -79,6 +83,7 @@ func (c *ApiController) AddToken() { c.ServeJSON() } +// DeleteToken // @Title DeleteToken // @Description delete token // @Param body body object.Token true "Details of the token" @@ -95,6 +100,7 @@ func (c *ApiController) DeleteToken() { c.ServeJSON() } +// GetOAuthToken // @Title GetOAuthToken // @Description get oAuth token // @Param grant_type query string true "oAuth grant type" diff --git a/controllers/user.go b/controllers/user.go index 4fca41cb..c5371b30 100644 --- a/controllers/user.go +++ b/controllers/user.go @@ -23,6 +23,7 @@ import ( "github.com/casbin/casdoor/original" ) +// GetGlobalUsers // @Title GetGlobalUsers // @Description get global users // @Success 200 {array} object.User The Response object @@ -32,6 +33,7 @@ func (c *ApiController) GetGlobalUsers() { c.ServeJSON() } +// GetUsers // @Title GetUsers // @Description // @Param owner query string true "The owner of users" @@ -44,6 +46,7 @@ func (c *ApiController) GetUsers() { c.ServeJSON() } +// GetUser // @Title GetUser // @Description get user // @Param id query string true "The id of the user" @@ -56,6 +59,7 @@ func (c *ApiController) GetUser() { c.ServeJSON() } +// UpdateUser // @Title UpdateUser // @Description update user // @Param id query string true "The id of the user" @@ -86,6 +90,7 @@ func (c *ApiController) UpdateUser() { c.ServeJSON() } +// AddUser // @Title AddUser // @Description add user // @Param body body object.User true "The details of the user" @@ -102,6 +107,7 @@ func (c *ApiController) AddUser() { c.ServeJSON() } +// DeleteUser // @Title DeleteUser // @Description delete user // @Param body body object.User true "The details of the user" @@ -118,6 +124,7 @@ func (c *ApiController) DeleteUser() { c.ServeJSON() } +// GetEmailAndPhone // @Title GetEmailAndPhone // @Description get email and phone by username // @Param username formData string true "The username of the user" @@ -156,6 +163,7 @@ func (c *ApiController) GetEmailAndPhone() { c.ServeJSON() } +// SetPassword // @Title SetPassword // @Description set password // @Param userOwner formData string true "The owner of the user" @@ -209,11 +217,9 @@ func (c *ApiController) SetPassword() { c.ResponseError(msg) return } - } else { - } - if strings.Index(newPassword, " ") >= 0 { + if strings.Contains(newPassword, " ") { c.ResponseError("New password cannot contain blank space.") return } diff --git a/controllers/util.go b/controllers/util.go index fba4d047..0bd1fe46 100644 --- a/controllers/util.go +++ b/controllers/util.go @@ -24,6 +24,7 @@ import ( var defaultHttpClient *http.Client var proxyHttpClient *http.Client +// InitHttpClient ... func InitHttpClient() { // not use proxy defaultHttpClient = http.DefaultClient @@ -54,6 +55,7 @@ func InitHttpClient() { //println("Response status: %s", resp.Status) } +// ResponseError ... func (c *ApiController) ResponseError(error string, data ...interface{}) { resp := Response{Status: "error", Msg: error} switch len(data) { @@ -67,11 +69,13 @@ func (c *ApiController) ResponseError(error string, data ...interface{}) { c.ServeJSON() } +// ResponseErrorWithData ... func (c *ApiController) ResponseErrorWithData(error string, data interface{}) { c.Data["json"] = Response{Status: "error", Msg: error, Data: data} c.ServeJSON() } +// RequireSignedIn ... func (c *ApiController) RequireSignedIn() (string, bool) { userId := c.GetSessionUsername() if userId == "" { diff --git a/controllers/verification.go b/controllers/verification.go index f86b7914..7769791e 100644 --- a/controllers/verification.go +++ b/controllers/verification.go @@ -33,6 +33,7 @@ func (c *ApiController) getCurrentUser() *object.User { return user } +// SendVerificationCode ... func (c *ApiController) SendVerificationCode() { destType := c.Ctx.Request.Form.Get("type") dest := c.Ctx.Request.Form.Get("dest") @@ -42,7 +43,7 @@ func (c *ApiController) SendVerificationCode() { checkKey := c.Ctx.Request.Form.Get("checkKey") remoteAddr := util.GetIPFromRequest(c.Ctx.Request) - if len(destType) == 0 || len(dest) == 0 || len(orgId) == 0 || strings.Index(orgId, "/") < 0 || len(checkType) == 0 || len(checkId) == 0 || len(checkKey) == 0 { + if len(destType) == 0 || len(dest) == 0 || len(orgId) == 0 || !strings.Contains(orgId, "/") || len(checkType) == 0 || len(checkId) == 0 || len(checkKey) == 0 { c.ResponseError("Missing parameter.") return } @@ -97,6 +98,7 @@ func (c *ApiController) SendVerificationCode() { c.ServeJSON() } +// ResetEmailOrPhone ... func (c *ApiController) ResetEmailOrPhone() { userId, ok := c.RequireSignedIn() if !ok { diff --git a/go.mod b/go.mod index 75ed0139..60f34455 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/satori/go.uuid v1.2.0 // indirect github.com/smartystreets/goconvey v1.6.4 // indirect github.com/thanhpk/randstr v1.0.4 - golang.org/x/net v0.0.0-20201110031124-69a78807bb2b + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect diff --git a/go.sum b/go.sum index 449d4b39..2a021c72 100644 --- a/go.sum +++ b/go.sum @@ -386,8 +386,9 @@ 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-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= 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= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -435,8 +436,11 @@ 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-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= 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= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/idp/dingtalk.go b/idp/dingtalk.go index c8aa08b0..a48ef3bd 100644 --- a/idp/dingtalk.go +++ b/idp/dingtalk.go @@ -20,7 +20,6 @@ import ( "crypto/sha256" "encoding/base64" "encoding/json" - "errors" "fmt" "io" "io/ioutil" @@ -48,6 +47,7 @@ type DingTalkIdProvider struct { Config *oauth2.Config } +// NewDingTalkIdProvider ... func NewDingTalkIdProvider(clientId string, clientSecret string, redirectUrl string) *DingTalkIdProvider { idp := &DingTalkIdProvider{} @@ -57,6 +57,7 @@ func NewDingTalkIdProvider(clientId string, clientSecret string, redirectUrl str return idp } +// SetHttpClient ... func (idp *DingTalkIdProvider) SetHttpClient(client *http.Client) { idp.Client = client } @@ -136,7 +137,7 @@ func (idp *DingTalkIdProvider) GetToken(code string) (*oauth2.Token, error) { _ = json.Unmarshal(body, &info) errCode := info.Errcode if errCode != 0 { - return nil, errors.New(fmt.Sprintf("%d: %s", errCode, info.Errmsg)) + return nil, fmt.Errorf("%d: %s", errCode, info.Errmsg) } u2 := fmt.Sprintf("%s?appkey=%s&appsecret=%s", idp.Config.Endpoint.TokenURL, idp.Config.ClientID, idp.Config.ClientSecret) @@ -151,7 +152,7 @@ func (idp *DingTalkIdProvider) GetToken(code string) (*oauth2.Token, error) { tokenResp := DingTalkAccessToken{} _ = json.Unmarshal(body, &tokenResp) if tokenResp.ErrCode != 0 { - return nil, errors.New(fmt.Sprintf("%d: %s", tokenResp.ErrCode, tokenResp.ErrMsg)) + return nil, fmt.Errorf("%d: %s", tokenResp.ErrCode, tokenResp.ErrMsg) } // use unionid to get userid @@ -183,6 +184,7 @@ type UnionIdResponse struct { RequestId string `json:"request_id"` } +// GetUseridByUnionid ... func (idp *DingTalkIdProvider) GetUseridByUnionid(accesstoken, unionid string) (userid string, err error) { u := fmt.Sprintf("https://oapi.dingtalk.com/topapi/user/getbyunionid?access_token=%s&unionid=%s", accesstoken, unionid) @@ -195,7 +197,7 @@ func (idp *DingTalkIdProvider) GetUseridByUnionid(accesstoken, unionid string) ( _ = json.Unmarshal([]byte(useridInfo), &uresp) errcode := uresp.Errcode if errcode != 0 { - return "", errors.New(fmt.Sprintf("%d: %s", errcode, uresp.Errmsg)) + return "", fmt.Errorf("%d: %s", errcode, uresp.Errmsg) } return uresp.Result.Userid, nil } diff --git a/idp/github.go b/idp/github.go index 81b6b524..36c78c80 100644 --- a/idp/github.go +++ b/idp/github.go @@ -61,7 +61,7 @@ func (idp *GithubIdProvider) getConfig() *oauth2.Config { } func (idp *GithubIdProvider) GetToken(code string) (*oauth2.Token, error) { - ctx := context.WithValue(oauth2.NoContext, oauth2.HTTPClient, idp.Client) + ctx := context.WithValue(context.Background(), oauth2.HTTPClient, idp.Client) return idp.Config.Exchange(ctx, code) } diff --git a/idp/google.go b/idp/google.go index 3875cabd..a0c84275 100644 --- a/idp/google.go +++ b/idp/google.go @@ -61,7 +61,7 @@ func (idp *GoogleIdProvider) getConfig() *oauth2.Config { } func (idp *GoogleIdProvider) GetToken(code string) (*oauth2.Token, error) { - ctx := context.WithValue(oauth2.NoContext, oauth2.HTTPClient, idp.Client) + ctx := context.WithValue(context.Background(), oauth2.HTTPClient, idp.Client) return idp.Config.Exchange(ctx, code) } diff --git a/idp/linkedin.go b/idp/linkedin.go index 077a7e2e..110893b7 100644 --- a/idp/linkedin.go +++ b/idp/linkedin.go @@ -89,18 +89,18 @@ func (idp *LinkedInIdProvider) GetToken(code string) (*oauth2.Token, error) { if err != nil { return nil, err } - + tokenResp := LinkedInAccessToken{} if err = json.Unmarshal(rbs, &tokenResp); err != nil { return nil, err } - + token := &oauth2.Token{ - AccessToken: tokenResp.AccessToken, + AccessToken: tokenResp.AccessToken, TokenType: "Bearer", - Expiry: time.Unix(time.Now().Unix()+tokenResp.ExpiresIn, 0), + Expiry: time.Unix(time.Now().Unix()+tokenResp.ExpiresIn, 0), } - + return token, nil } @@ -186,14 +186,14 @@ func (idp *LinkedInIdProvider) GetToken(code string) (*oauth2.Token, error) { type LinkedInUserInfo struct { FirstName struct { - Localized map[string]string `json:"localized"` + Localized map[string]string `json:"localized"` PreferredLocale struct { Country string `json:"country"` Language string `json:"language"` } `json:"preferredLocale"` } `json:"firstName"` LastName struct { - Localized map[string]string `json:"localized"` + Localized map[string]string `json:"localized"` PreferredLocale struct { Country string `json:"country"` Language string `json:"language"` @@ -301,7 +301,7 @@ func (idp *LinkedInIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro userInfo := UserInfo{ Id: linkedInUserInfo.Id, DisplayName: username, - Username: username, + Username: username, Email: linkedInUserEmail.Elements[0].Handle.EmailAddress, AvatarUrl: linkedInUserInfo.ProfilePicture.DisplayImage1.Elements[0].Identifiers[0].Identifier, } diff --git a/idp/provider.go b/idp/provider.go index a4ae0160..57aba69a 100644 --- a/idp/provider.go +++ b/idp/provider.go @@ -34,6 +34,7 @@ type IdProvider interface { GetUserInfo(token *oauth2.Token) (*UserInfo, error) } +// GetIdProvider ... func GetIdProvider(providerType string, clientId string, clientSecret string, redirectUrl string) IdProvider { if providerType == "GitHub" { return NewGithubIdProvider(clientId, clientSecret, redirectUrl) diff --git a/idp/qq.go b/idp/qq.go index 25c3c8e9..1a894e94 100644 --- a/idp/qq.go +++ b/idp/qq.go @@ -173,7 +173,7 @@ func (idp *QqIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) { } if qqUserInfo.Ret != 0 { - return nil, errors.New(fmt.Sprintf("ret expected 0, got %d", qqUserInfo.Ret)) + return nil, fmt.Errorf("ret expected 0, got %d", qqUserInfo.Ret) } userInfo := UserInfo{ diff --git a/idp/wechat.go b/idp/wechat.go index f2aa1340..e845f21a 100644 --- a/idp/wechat.go +++ b/idp/wechat.go @@ -99,7 +99,7 @@ func (idp *WeChatIdProvider) GetToken(code string) (*oauth2.Token, error) { } var wechatAccessToken WechatAccessToken - if err = json.Unmarshal([]byte(buf.String()), &wechatAccessToken); err != nil { + if err = json.Unmarshal(buf.Bytes(), &wechatAccessToken); err != nil { return nil, err } @@ -168,7 +168,7 @@ func (idp *WeChatIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) if err != nil { return nil, err } - if err = json.Unmarshal([]byte(buf.String()), &wechatUserInfo); err != nil { + if err = json.Unmarshal(buf.Bytes(), &wechatUserInfo); err != nil { return nil, err } diff --git a/object/adapter.go b/object/adapter.go index 05c8ac8e..35cb7257 100644 --- a/object/adapter.go +++ b/object/adapter.go @@ -99,7 +99,7 @@ func (a *Adapter) open() { } func (a *Adapter) close() { - a.Engine.Close() + _ = a.Engine.Close() a.Engine = nil } diff --git a/object/check.go b/object/check.go index 1e123ce1..97c2a721 100644 --- a/object/check.go +++ b/object/check.go @@ -24,7 +24,7 @@ import ( var reWhiteSpace *regexp.Regexp func init() { - reWhiteSpace, _ = regexp.Compile("\\s") + reWhiteSpace, _ = regexp.Compile(`\s`) } func CheckUserSignup(application *Application, organization *Organization, username string, password string, displayName string, email string, phone string, affiliation string) string { diff --git a/object/ldap.go b/object/ldap.go index 83771568..0e4179c2 100644 --- a/object/ldap.go +++ b/object/ldap.go @@ -152,43 +152,30 @@ func (l *ldapConn) GetLdapUsers(baseDn string) ([]ldapUser, error) { switch attribute.Name { case "uidNumber": ldapUserItem.UidNumber = attribute.Values[0] - break case "uid": ldapUserItem.Uid = attribute.Values[0] - break case "cn": ldapUserItem.Cn = attribute.Values[0] - break case "gidNumber": ldapUserItem.GidNumber = attribute.Values[0] - break case "entryUUID": ldapUserItem.Uuid = attribute.Values[0] - break case "mail": ldapUserItem.Mail = attribute.Values[0] - break case "email": ldapUserItem.Email = attribute.Values[0] - break case "emailAddress": ldapUserItem.EmailAddress = attribute.Values[0] - break case "telephoneNumber": ldapUserItem.TelephoneNumber = attribute.Values[0] - break case "mobile": ldapUserItem.Mobile = attribute.Values[0] - break case "mobileTelephoneNumber": ldapUserItem.MobileTelephoneNumber = attribute.Values[0] - break case "registeredAddress": ldapUserItem.RegisteredAddress = attribute.Values[0] - break case "postalAddress": ldapUserItem.PostalAddress = attribute.Values[0] - break } } ldapUsers = append(ldapUsers, ldapUserItem) @@ -348,7 +335,7 @@ func CheckLdapUuidExist(owner string, uuids []string) []string { // } //} - err := adapter.Engine.Where(fmt.Sprintf("ldap IN (%s) AND owner = ?", "'" + strings.Join(uuids, "','") + "'"), owner).Find(&results) + err := adapter.Engine.Where(fmt.Sprintf("ldap IN (%s) AND owner = ?", "'"+strings.Join(uuids, "','")+"'"), owner).Find(&results) if err != nil { panic(err) } diff --git a/object/provider.go b/object/provider.go index 04d48ac6..b37943dd 100644 --- a/object/provider.go +++ b/object/provider.go @@ -43,8 +43,8 @@ type Provider struct { AppId string `xorm:"varchar(100)" json:"appId"` Endpoint string `xorm:"varchar(100)" json:"endpoint"` - Domain string `xorm:"varchar(100)" json:"domain"` - Bucket string `xorm:"varchar(100)" json:"bucket"` + Domain string `xorm:"varchar(100)" json:"domain"` + Bucket string `xorm:"varchar(100)" json:"bucket"` ProviderUrl string `xorm:"varchar(200)" json:"providerUrl"` } diff --git a/object/record.go b/object/record.go index e0d3b2c8..6a07dddb 100644 --- a/object/record.go +++ b/object/record.go @@ -19,8 +19,8 @@ import ( ) type Records struct { - Id int `xorm:"int notnull pk autoincr" json:"id"` - Record util.Record `xorm:"extends"` + Id int `xorm:"int notnull pk autoincr" json:"id"` + Record util.Record `xorm:"extends"` } func AddRecord(record *util.Record) bool { diff --git a/object/user.go b/object/user.go index ce11f574..c85aff1e 100644 --- a/object/user.go +++ b/object/user.go @@ -132,9 +132,9 @@ func GetLastUser(owner string) *User { if existed { return &user - } else { - return nil } + + return nil } func UpdateUser(id string, user *User) bool { diff --git a/object/user_test.go b/object/user_test.go index 64c436fd..5364d292 100644 --- a/object/user_test.go +++ b/object/user_test.go @@ -16,6 +16,7 @@ package object import ( "fmt" + "reflect" "testing" "github.com/casbin/casdoor/util" @@ -78,3 +79,27 @@ func TestGetSaltedPassword(t *testing.T) { salt := "123" fmt.Printf("%s -> %s\n", password, getSaltedPassword(password, salt)) } + +func TestGetMaskedUsers(t *testing.T) { + type args struct { + users []*User + } + tests := []struct { + name string + args args + want []*User + }{ + { + name: "1", + args: args{users: []*User{{Password: "casdoor"},{Password: "casbin"}}}, + want: []*User{{Password: "***"},{Password: "***"}}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := GetMaskedUsers(tt.args.users); !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetMaskedUsers() = %v, want %v", got, tt.want) + } + }) + } +} \ No newline at end of file diff --git a/routers/record.go b/routers/record.go index 6cfe9731..b397e978 100644 --- a/routers/record.go +++ b/routers/record.go @@ -50,15 +50,15 @@ func getUserByClientIdSecret(ctx *context.Context) string { if app == nil || app.ClientSecret != clientSecret { return "" } - return app.Organization+"/"+app.Name + return app.Organization + "/" + app.Name } func RecordMessage(ctx *context.Context) { if ctx.Request.URL.Path != "/api/login" { user := getUser(ctx) - userinfo := strings.Split(user,"/") + userinfo := strings.Split(user, "/") if user == "" { - userinfo = append(userinfo,"") + userinfo = append(userinfo, "") } record := util.Records(ctx) record.Organization = userinfo[0] @@ -67,4 +67,3 @@ func RecordMessage(ctx *context.Context) { object.AddRecord(record) } } - diff --git a/routers/router.go b/routers/router.go index 2654ce1f..fe9b71fe 100644 --- a/routers/router.go +++ b/routers/router.go @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package routers // @APIVersion 1.0.0 // @Title Casdoor API // @Description Documentation of Casdoor API @@ -99,4 +100,3 @@ func initAPI() { beego.Router("/api/send-email", &controllers.ApiController{}, "POST:SendEmail") beego.Router("/api/send-sms", &controllers.ApiController{}, "POST:SendSms") } - diff --git a/util/record.go b/util/record.go index 5ea72b8c..4f17f2f5 100644 --- a/util/record.go +++ b/util/record.go @@ -21,12 +21,12 @@ import ( ) type Record struct { - ClientIp string `xorm:"varchar(100)" json:"clientIp"` - Timestamp string `xorm:"varchar(100)" json:"timestamp"` - Organization string `xorm:"varchar(100)" json:"organization"` - Username string `xorm:"varchar(100)" json:"username"` - RequestUri string `xorm:"varchar(1000)" json:"requestUri"` - Action string `xorm:"varchar(1000)" json:"action"` + ClientIp string `xorm:"varchar(100)" json:"clientIp"` + Timestamp string `xorm:"varchar(100)" json:"timestamp"` + Organization string `xorm:"varchar(100)" json:"organization"` + Username string `xorm:"varchar(100)" json:"username"` + RequestUri string `xorm:"varchar(1000)" json:"requestUri"` + Action string `xorm:"varchar(1000)" json:"action"` } func Records(ctx *context.Context) *Record { diff --git a/util/regex.go b/util/regex.go index b0b74907..1cc0b357 100644 --- a/util/regex.go +++ b/util/regex.go @@ -23,7 +23,7 @@ var rePhoneCn *regexp.Regexp func init() { // https://learnku.com/articles/31543 - rePhoneCn, _ = regexp.Compile("^1(3\\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\\d|9[0-35-9])\\d{8}$") + rePhoneCn, _ = regexp.Compile(`^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$`) } func IsEmailValid(email string) bool {