Skip to content

Commit fff336c

Browse files
authored
Merge pull request #3 from daystram/dev
2 parents 18a2140 + c597744 commit fff336c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+3641
-501
lines changed

docker-compose.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,13 @@ services:
1414
volumes:
1515
- /opt/redis:/data
1616
restart: always
17+
proxy:
18+
image: nginx:1.18-alpine
19+
ports:
20+
- "80:80"
21+
extra_hosts:
22+
- "host:${LOCAL_IP}"
23+
volumes:
24+
- /opt/nginx:/etc/nginx
25+
restart: always
26+

nginx.conf

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
events {}
2+
http {
3+
server {
4+
listen 80;
5+
server_name localhost;
6+
7+
location / {
8+
proxy_pass http://host:8080;
9+
proxy_set_header Host $host;
10+
}
11+
12+
location /oauth {
13+
proxy_pass http://host:9000;
14+
proxy_set_header Host $host;
15+
}
16+
17+
location /api {
18+
proxy_pass http://host:9000;
19+
proxy_set_header Host $host;
20+
}
21+
22+
location /docs {
23+
proxy_pass http://host:9000;
24+
proxy_set_header Host $host;
25+
}
26+
}
27+
}
28+
Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,37 @@
11
package middleware
22

33
import (
4-
"errors"
5-
"fmt"
64
"net/http"
75
"strings"
86

9-
"github.com/dgrijalva/jwt-go"
107
"github.com/gin-gonic/gin"
118

12-
"github.com/daystram/ratify/ratify-be/config"
139
"github.com/daystram/ratify/ratify-be/constants"
1410
"github.com/daystram/ratify/ratify-be/datatransfers"
11+
"github.com/daystram/ratify/ratify-be/handlers"
12+
"github.com/daystram/ratify/ratify-be/models"
1513
)
1614

1715
func AuthMiddleware(c *gin.Context) {
18-
token := strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ")
19-
if token == "" {
16+
accessToken := strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ")
17+
if accessToken == "" {
2018
c.Set(constants.IsAuthenticatedKey, false)
2119
c.Next()
2220
return
2321
}
24-
claims, err := parseToken(token, config.AppConfig.JWTSecret)
25-
if err != nil {
26-
c.AbortWithStatusJSON(http.StatusUnauthorized, datatransfers.Response{Error: err.Error()})
22+
var err error
23+
var tokenInfo datatransfers.TokenIntrospection
24+
if tokenInfo, err = handlers.Handler.IntrospectAccessToken(accessToken); err != nil || !tokenInfo.Active {
25+
c.AbortWithStatusJSON(http.StatusUnauthorized, datatransfers.APIResponse{Code: "invalid_token", Error: "invalid access_token"})
26+
return
27+
}
28+
var user models.User
29+
if user, err = handlers.Handler.RetrieveUserBySubject(tokenInfo.Subject); err != nil {
30+
c.AbortWithStatusJSON(http.StatusUnauthorized, datatransfers.APIResponse{Code: "invalid_token", Error: err.Error()})
2731
return
2832
}
2933
c.Set(constants.IsAuthenticatedKey, true)
30-
c.Set(constants.UserSubjectKey, claims.Subject)
31-
c.Set(constants.IsSuperuserKey, claims.IsSuperuser)
34+
c.Set(constants.UserSubjectKey, user.Subject)
35+
c.Set(constants.IsSuperuserKey, user.Superuser)
3236
c.Next()
3337
}
34-
35-
func parseToken(tokenString, secret string) (claims datatransfers.JWTClaims, err error) {
36-
if token, err := jwt.ParseWithClaims(tokenString, &claims, func(token *jwt.Token) (interface{}, error) {
37-
return []byte(secret), nil
38-
}); err != nil || !token.Valid {
39-
return datatransfers.JWTClaims{}, errors.New(fmt.Sprintf("invalid token. %s", err))
40-
}
41-
return
42-
}

ratify-be/controllers/v1/application.go

Lines changed: 92 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -21,46 +21,45 @@ import (
2121
// @Router /api/v1/application/{client_id} [GET]
2222
func GETOneApplicationDetail(c *gin.Context) {
2323
var err error
24-
// fetch clientID
25-
clientID := strings.TrimPrefix(c.Param("client_id"), "/") // trim due to router catch-all
26-
// get application
24+
// fetch application info
2725
var application models.Application
28-
if application, err = handlers.Handler.RetrieveApplication(clientID); err != nil {
29-
c.JSON(http.StatusNotFound, datatransfers.Response{Error: "application not found"})
26+
application.ClientID = strings.TrimPrefix(c.Param("client_id"), "/") // trim due to router catch-all
27+
if application, err = handlers.Handler.RetrieveApplication(application.ClientID); err != nil {
28+
c.JSON(http.StatusNotFound, datatransfers.APIResponse{Error: "application not found"})
3029
return
3130
}
32-
// check ownership
33-
if application.Owner.Subject != c.GetString(constants.UserSubjectKey) {
34-
c.JSON(http.StatusOK, datatransfers.Response{Data: datatransfers.ApplicationInfo{
31+
// check superuser
32+
if !c.GetBool(constants.IsSuperuserKey) {
33+
c.JSON(http.StatusOK, datatransfers.APIResponse{Data: datatransfers.ApplicationInfo{
3534
Name: application.Name,
3635
}})
3736
return
3837
}
39-
c.JSON(http.StatusOK, datatransfers.Response{Data: datatransfers.ApplicationInfo{
40-
ClientID: application.ClientID,
41-
ClientSecret: application.ClientSecret,
42-
Name: application.Name,
43-
Description: application.Description,
44-
LoginURL: application.LoginURL,
45-
CallbackURL: application.CallbackURL,
46-
LogoutURL: application.LogoutURL,
47-
Metadata: application.Metadata,
48-
CreatedAt: application.CreatedAt,
38+
c.JSON(http.StatusOK, datatransfers.APIResponse{Data: datatransfers.ApplicationInfo{
39+
ClientID: application.ClientID,
40+
Name: application.Name,
41+
Description: application.Description,
42+
LoginURL: application.LoginURL,
43+
CallbackURL: application.CallbackURL,
44+
LogoutURL: application.LogoutURL,
45+
Metadata: application.Metadata,
46+
Locked: application.Locked,
47+
CreatedAt: application.CreatedAt,
4948
}})
5049
return
5150
}
5251

53-
// @Summary Get owned applications
52+
// @Summary Get all applications
5453
// @Tags application
5554
// @Security BearerAuth
5655
// @Success 200 "OK"
5756
// @Router /api/v1/application [GET]
58-
func GETOwnedApplications(c *gin.Context) {
57+
func GETApplicationList(c *gin.Context) {
5958
var err error
6059
// get all owned applications
6160
var applications []models.Application
62-
if applications, err = handlers.Handler.RetrieveOwnedApplications(c.GetString(constants.UserSubjectKey)); err != nil {
63-
c.JSON(http.StatusNotFound, datatransfers.Response{Error: "cannot retrieve applications"})
61+
if applications, err = handlers.Handler.RetrieveAllApplications(); err != nil {
62+
c.JSON(http.StatusNotFound, datatransfers.APIResponse{Error: "cannot retrieve applications"})
6463
return
6564
}
6665
var applicationsResponse []datatransfers.ApplicationInfo
@@ -72,7 +71,7 @@ func GETOwnedApplications(c *gin.Context) {
7271
CreatedAt: application.CreatedAt,
7372
})
7473
}
75-
c.JSON(http.StatusOK, datatransfers.Response{Data: applicationsResponse})
74+
c.JSON(http.StatusOK, datatransfers.APIResponse{Data: applicationsResponse})
7675
return
7776
}
7877

@@ -87,15 +86,16 @@ func POSTApplication(c *gin.Context) {
8786
// fetch application info
8887
var applicationInfo datatransfers.ApplicationInfo
8988
if err = c.ShouldBindJSON(&applicationInfo); err != nil {
90-
c.JSON(http.StatusBadRequest, datatransfers.Response{Error: err.Error()})
89+
c.JSON(http.StatusBadRequest, datatransfers.APIResponse{Error: err.Error()})
9190
return
9291
}
9392
// register application
94-
if applicationInfo.ClientID, err = handlers.Handler.RegisterApplication(applicationInfo, c.GetString(constants.UserSubjectKey)); err != nil {
95-
c.JSON(http.StatusInternalServerError, datatransfers.Response{Error: "failed updating application"})
93+
var clientSecret string
94+
if applicationInfo.ClientID, clientSecret, err = handlers.Handler.RegisterApplication(applicationInfo, c.GetString(constants.UserSubjectKey)); err != nil {
95+
c.JSON(http.StatusInternalServerError, datatransfers.APIResponse{Error: "failed updating application"})
9696
return
9797
}
98-
c.JSON(http.StatusOK, datatransfers.Response{Data: gin.H{"client_id": applicationInfo.ClientID}})
98+
c.JSON(http.StatusOK, datatransfers.APIResponse{Data: gin.H{"client_id": applicationInfo.ClientID, "client_secret": clientSecret}})
9999
return
100100
}
101101

@@ -109,27 +109,83 @@ func POSTApplication(c *gin.Context) {
109109
func PUTApplication(c *gin.Context) {
110110
var err error
111111
// fetch application info
112-
clientID := c.Param("client_id")
113112
var applicationInfo datatransfers.ApplicationInfo
114113
if err = c.ShouldBindJSON(&applicationInfo); err != nil {
115-
c.JSON(http.StatusBadRequest, datatransfers.Response{Error: err.Error()})
114+
c.JSON(http.StatusBadRequest, datatransfers.APIResponse{Error: err.Error()})
116115
return
117116
}
118-
// check ownership
119117
var application models.Application
120-
if application, err = handlers.Handler.RetrieveApplication(clientID); err != nil {
121-
c.JSON(http.StatusNotFound, datatransfers.Response{Error: "application not found"})
118+
application.ClientID = strings.TrimPrefix(c.Param("client_id"), "/")
119+
if application, err = handlers.Handler.RetrieveApplication(application.ClientID); err != nil {
120+
c.JSON(http.StatusNotFound, datatransfers.APIResponse{Error: "application not found"})
122121
return
123122
}
124-
if application.Owner.Subject != c.GetString(constants.UserSubjectKey) {
125-
c.JSON(http.StatusUnauthorized, datatransfers.Response{Error: "access to resource unauthorized"})
123+
// checked locked flag
124+
if application.Locked &&
125+
(applicationInfo.LoginURL != application.LoginURL ||
126+
applicationInfo.CallbackURL != application.CallbackURL ||
127+
applicationInfo.LogoutURL != application.LogoutURL) {
128+
c.JSON(http.StatusBadRequest, datatransfers.APIResponse{Error: "application is locked"})
126129
return
127130
}
128131
// update application
129132
if err = handlers.Handler.UpdateApplication(applicationInfo); err != nil {
130-
c.JSON(http.StatusInternalServerError, datatransfers.Response{Error: "failed updating application"})
133+
c.JSON(http.StatusInternalServerError, datatransfers.APIResponse{Error: "failed updating application"})
134+
return
135+
}
136+
c.JSON(http.StatusOK, datatransfers.APIResponse{})
137+
return
138+
}
139+
140+
// @Summary Delete application
141+
// @Tags application
142+
// @Security BearerAuth
143+
// @Param client_id path string true "Client ID"
144+
// @Success 200 "OK"
145+
// @Router /api/v1/application/{client_id} [DELETE]
146+
func DELETEApplication(c *gin.Context) {
147+
var err error
148+
// fetch application info
149+
var application models.Application
150+
application.ClientID = strings.TrimPrefix(c.Param("client_id"), "/")
151+
if application, err = handlers.Handler.RetrieveApplication(application.ClientID); err != nil {
152+
c.JSON(http.StatusNotFound, datatransfers.APIResponse{Error: "application not found"})
153+
return
154+
}
155+
// checked locked flag
156+
if application.Locked {
157+
c.JSON(http.StatusBadRequest, datatransfers.APIResponse{Error: "application is locked"})
158+
return
159+
}
160+
// delete application
161+
if err = handlers.Handler.DeleteApplication(application.ClientID); err != nil {
162+
c.JSON(http.StatusInternalServerError, datatransfers.APIResponse{Error: "failed deleting application"})
163+
return
164+
}
165+
c.JSON(http.StatusOK, datatransfers.APIResponse{})
166+
return
167+
}
168+
169+
// @Summary Revoke application secret
170+
// @Tags application
171+
// @Security BearerAuth
172+
// @Param client_id path string true "Client ID"
173+
// @Success 200 "OK"
174+
// @Router /api/v1/application/{client_id}/revoke [PUT]
175+
func PUTApplicationRevokeSecret(c *gin.Context) {
176+
var err error
177+
// fetch application info
178+
clientID := strings.TrimPrefix(c.Param("client_id"), "/")
179+
if _, err = handlers.Handler.RetrieveApplication(clientID); err != nil {
180+
c.JSON(http.StatusNotFound, datatransfers.APIResponse{Error: "application not found"})
181+
return
182+
}
183+
// renew application client_secret
184+
var clientSecret string
185+
if clientSecret, err = handlers.Handler.RenewApplicationClientSecret(clientID); err != nil {
186+
c.JSON(http.StatusInternalServerError, datatransfers.APIResponse{Error: "failed renewing application client_secret"})
131187
return
132188
}
133-
c.JSON(http.StatusOK, datatransfers.Response{})
189+
c.JSON(http.StatusOK, datatransfers.APIResponse{Data: gin.H{"client_secret": clientSecret}})
134190
return
135191
}

ratify-be/controllers/v1/auth.go

Lines changed: 0 additions & 52 deletions
This file was deleted.

ratify-be/controllers/v1/form.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package v1
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
7+
"github.com/gin-gonic/gin"
8+
9+
"github.com/daystram/ratify/ratify-be/datatransfers"
10+
"github.com/daystram/ratify/ratify-be/handlers"
11+
)
12+
13+
// @Summary Check unique form field
14+
// @Tags form
15+
// @Param uniqueRequest body datatransfers.UniqueCheckRequest true "Unique query"
16+
// @Success 200 "OK"
17+
// @Router /api/v1/form/unique [POST]
18+
func POSTUniqueCheck(c *gin.Context) {
19+
var err error
20+
var uniqueRequest datatransfers.UniqueCheckRequest
21+
if err = c.ShouldBindJSON(&uniqueRequest); err != nil {
22+
c.JSON(http.StatusBadRequest, datatransfers.APIResponse{Error: err.Error()})
23+
return
24+
}
25+
unique := false
26+
switch uniqueRequest.Field {
27+
case "user:username":
28+
_, err = handlers.Handler.RetrieveUserByUsername(uniqueRequest.Value)
29+
unique = err != nil
30+
case "user:email":
31+
_, err = handlers.Handler.RetrieveUserByEmail(uniqueRequest.Value)
32+
unique = err != nil
33+
default:
34+
c.JSON(http.StatusBadRequest, datatransfers.APIResponse{Error: fmt.Sprintf("unsupported field %s", uniqueRequest.Field)})
35+
return
36+
}
37+
c.JSON(http.StatusOK, datatransfers.APIResponse{Data: unique})
38+
return
39+
}

0 commit comments

Comments
 (0)