Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
D
dex
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
dex
Commits
ed7e9434
Commit
ed7e9434
authored
Oct 27, 2016
by
rithu leena john
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
api: add gRPC endpoints for creating, updating and deleting passwords
parent
acf3d638
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
207 additions
and
4 deletions
+207
-4
api.pb.go
api/api.pb.go
+0
-0
api.proto
api/api.proto
+49
-0
api.go
server/api.go
+99
-2
api_test.go
server/api_test.go
+58
-0
storage.go
storage/storage.go
+1
-2
No files found.
api/api.pb.go
View file @
ed7e9434
This diff is collapsed.
Click to expand it.
api/api.proto
View file @
ed7e9434
...
@@ -37,10 +37,59 @@ message DeleteClientResp {
...
@@ -37,10 +37,59 @@ message DeleteClientResp {
// TODO(ericchiang): expand this.
// TODO(ericchiang): expand this.
// Password is an email for password mapping managed by the storage.
message
Password
{
string
email
=
1
;
// Currently we do not accept plain text passwords. Could be an option in the future.
bytes
hash
=
2
;
string
username
=
3
;
string
user_id
=
4
;
}
// CreatePasswordReq is a request to make a password.
message
CreatePasswordReq
{
Password
password
=
1
;
}
// CreatePasswordResp returns the response from creating a password.
message
CreatePasswordResp
{
bool
already_exists
=
1
;
}
// UpdatePasswordReq is a request to modify an existing password.
message
UpdatePasswordReq
{
// The email used to lookup the password. This field cannot be modified
string
email
=
1
;
bytes
new_hash
=
2
;
string
new_username
=
3
;
}
// UpdatePasswordResp returns the response from modifying an existing password.
message
UpdatePasswordResp
{
bool
not_found
=
1
;
}
// DeletePasswordReq is a request to delete a password.
message
DeletePasswordReq
{
string
email
=
1
;
}
// DeletePasswordResp returns the response from deleting a password.
message
DeletePasswordResp
{
bool
not_found
=
1
;
}
// Dex represents the dex gRPC service.
// Dex represents the dex gRPC service.
service
Dex
{
service
Dex
{
// CreateClient attempts to create the client.
// CreateClient attempts to create the client.
rpc
CreateClient
(
CreateClientReq
)
returns
(
CreateClientResp
)
{};
rpc
CreateClient
(
CreateClientReq
)
returns
(
CreateClientResp
)
{};
// DeleteClient attempts to delete the provided client.
// DeleteClient attempts to delete the provided client.
rpc
DeleteClient
(
DeleteClientReq
)
returns
(
DeleteClientResp
)
{};
rpc
DeleteClient
(
DeleteClientReq
)
returns
(
DeleteClientResp
)
{};
// CreatePassword attempts to create the password.
rpc
CreatePassword
(
CreatePasswordReq
)
returns
(
CreatePasswordResp
)
{};
// UpdatePassword attempts to modify existing password.
rpc
UpdatePassword
(
UpdatePasswordReq
)
returns
(
UpdatePasswordResp
)
{};
// DeletePassword attempts to delete the password.
rpc
DeletePassword
(
DeletePasswordReq
)
returns
(
DeletePasswordResp
)
{};
}
}
server/api.go
View file @
ed7e9434
...
@@ -2,8 +2,10 @@ package server
...
@@ -2,8 +2,10 @@ package server
import
(
import
(
"errors"
"errors"
"fmt"
"log"
"log"
"golang.org/x/crypto/bcrypt"
"golang.org/x/net/context"
"golang.org/x/net/context"
"github.com/coreos/dex/api"
"github.com/coreos/dex/api"
...
@@ -43,7 +45,7 @@ func (d dexAPI) CreateClient(ctx context.Context, req *api.CreateClientReq) (*ap
...
@@ -43,7 +45,7 @@ func (d dexAPI) CreateClient(ctx context.Context, req *api.CreateClientReq) (*ap
if
err
:=
d
.
s
.
CreateClient
(
c
);
err
!=
nil
{
if
err
:=
d
.
s
.
CreateClient
(
c
);
err
!=
nil
{
log
.
Printf
(
"api: failed to create client: %v"
,
err
)
log
.
Printf
(
"api: failed to create client: %v"
,
err
)
// TODO(ericchiang): Surface "already exists" errors.
// TODO(ericchiang): Surface "already exists" errors.
return
nil
,
err
return
nil
,
fmt
.
Errorf
(
"create client: %v"
,
err
)
}
}
return
&
api
.
CreateClientResp
{
return
&
api
.
CreateClientResp
{
...
@@ -58,7 +60,102 @@ func (d dexAPI) DeleteClient(ctx context.Context, req *api.DeleteClientReq) (*ap
...
@@ -58,7 +60,102 @@ func (d dexAPI) DeleteClient(ctx context.Context, req *api.DeleteClientReq) (*ap
return
&
api
.
DeleteClientResp
{
NotFound
:
true
},
nil
return
&
api
.
DeleteClientResp
{
NotFound
:
true
},
nil
}
}
log
.
Printf
(
"api: failed to delete client: %v"
,
err
)
log
.
Printf
(
"api: failed to delete client: %v"
,
err
)
return
nil
,
err
return
nil
,
fmt
.
Errorf
(
"delete client: %v"
,
err
)
}
}
return
&
api
.
DeleteClientResp
{},
nil
return
&
api
.
DeleteClientResp
{},
nil
}
}
// checkCost returns an error if the hash provided does not meet minimum cost requirement
func
checkCost
(
hash
[]
byte
)
error
{
actual
,
err
:=
bcrypt
.
Cost
(
hash
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"parsing bcrypt hash: %v"
,
err
)
}
if
actual
<
bcrypt
.
DefaultCost
{
return
fmt
.
Errorf
(
"given hash cost = %d, does not meet minimum cost requirement = %d"
,
actual
,
bcrypt
.
DefaultCost
)
}
return
nil
}
func
(
d
dexAPI
)
CreatePassword
(
ctx
context
.
Context
,
req
*
api
.
CreatePasswordReq
)
(
*
api
.
CreatePasswordResp
,
error
)
{
if
req
.
Password
==
nil
{
return
nil
,
errors
.
New
(
"no password supplied"
)
}
if
req
.
Password
.
UserId
==
""
{
return
nil
,
errors
.
New
(
"no user ID supplied"
)
}
if
req
.
Password
.
Hash
!=
nil
{
if
err
:=
checkCost
(
req
.
Password
.
Hash
);
err
!=
nil
{
return
nil
,
err
}
}
else
{
return
nil
,
errors
.
New
(
"no hash of password supplied"
)
}
p
:=
storage
.
Password
{
Email
:
req
.
Password
.
Email
,
Hash
:
req
.
Password
.
Hash
,
Username
:
req
.
Password
.
Username
,
UserID
:
req
.
Password
.
UserId
,
}
if
err
:=
d
.
s
.
CreatePassword
(
p
);
err
!=
nil
{
log
.
Printf
(
"api: failed to create password: %v"
,
err
)
return
nil
,
fmt
.
Errorf
(
"create password: %v"
,
err
)
}
return
&
api
.
CreatePasswordResp
{},
nil
}
func
(
d
dexAPI
)
UpdatePassword
(
ctx
context
.
Context
,
req
*
api
.
UpdatePasswordReq
)
(
*
api
.
UpdatePasswordResp
,
error
)
{
if
req
.
Email
==
""
{
return
nil
,
errors
.
New
(
"no email supplied"
)
}
if
req
.
NewHash
==
nil
&&
req
.
NewUsername
==
""
{
return
nil
,
errors
.
New
(
"nothing to update"
)
}
if
req
.
NewHash
!=
nil
{
if
err
:=
checkCost
(
req
.
NewHash
);
err
!=
nil
{
return
nil
,
err
}
}
updater
:=
func
(
old
storage
.
Password
)
(
storage
.
Password
,
error
)
{
if
req
.
NewHash
!=
nil
{
old
.
Hash
=
req
.
NewHash
}
if
req
.
NewUsername
!=
""
{
old
.
Username
=
req
.
NewUsername
}
return
old
,
nil
}
if
err
:=
d
.
s
.
UpdatePassword
(
req
.
Email
,
updater
);
err
!=
nil
{
if
err
==
storage
.
ErrNotFound
{
return
&
api
.
UpdatePasswordResp
{
NotFound
:
true
},
nil
}
log
.
Printf
(
"api: failed to update password: %v"
,
err
)
return
nil
,
fmt
.
Errorf
(
"update password: %v"
,
err
)
}
return
&
api
.
UpdatePasswordResp
{},
nil
}
func
(
d
dexAPI
)
DeletePassword
(
ctx
context
.
Context
,
req
*
api
.
DeletePasswordReq
)
(
*
api
.
DeletePasswordResp
,
error
)
{
if
req
.
Email
==
""
{
return
nil
,
errors
.
New
(
"no email supplied"
)
}
err
:=
d
.
s
.
DeletePassword
(
req
.
Email
)
if
err
!=
nil
{
if
err
==
storage
.
ErrNotFound
{
return
&
api
.
DeletePasswordResp
{
NotFound
:
true
},
nil
}
log
.
Printf
(
"api: failed to delete password: %v"
,
err
)
return
nil
,
fmt
.
Errorf
(
"delete password: %v"
,
err
)
}
return
&
api
.
DeletePasswordResp
{},
nil
}
server/api_test.go
View file @
ed7e9434
package
server
package
server
import
(
"context"
"testing"
"github.com/coreos/dex/api"
"github.com/coreos/dex/storage/memory"
)
// Attempts to create, update and delete a test Password
func
TestPassword
(
t
*
testing
.
T
)
{
s
:=
memory
.
New
()
serv
:=
NewAPI
(
s
)
ctx
:=
context
.
Background
()
p
:=
api
.
Password
{
Email
:
"test@example.com"
,
// bcrypt hash of the value "test1" with cost 10
Hash
:
[]
byte
(
"$2a$10$XVMN/Fid.Ks4CXgzo8fpR.iU1khOMsP5g9xQeXuBm1wXjRX8pjUtO"
),
Username
:
"test"
,
UserId
:
"test123"
,
}
createReq
:=
api
.
CreatePasswordReq
{
Password
:
&
p
,
}
if
_
,
err
:=
serv
.
CreatePassword
(
ctx
,
&
createReq
);
err
!=
nil
{
t
.
Fatalf
(
"Unable to create password: %v"
,
err
)
}
updateReq
:=
api
.
UpdatePasswordReq
{
Email
:
"test@example.com"
,
NewUsername
:
"test1"
,
}
if
_
,
err
:=
serv
.
UpdatePassword
(
ctx
,
&
updateReq
);
err
!=
nil
{
t
.
Fatalf
(
"Unable to update password: %v"
,
err
)
}
pass
,
err
:=
s
.
GetPassword
(
updateReq
.
Email
)
if
err
!=
nil
{
t
.
Fatalf
(
"Unable to retrieve password: %v"
,
err
)
}
if
pass
.
Username
!=
updateReq
.
NewUsername
{
t
.
Fatalf
(
"UpdatePassword failed. Expected username %s retrieved %s"
,
updateReq
.
NewUsername
,
pass
.
Username
)
}
deleteReq
:=
api
.
DeletePasswordReq
{
Email
:
"test@example.com"
,
}
if
_
,
err
:=
serv
.
DeletePassword
(
ctx
,
&
deleteReq
);
err
!=
nil
{
t
.
Fatalf
(
"Unable to delete password: %v"
,
err
)
}
}
storage/storage.go
View file @
ed7e9434
...
@@ -238,8 +238,7 @@ type Password struct {
...
@@ -238,8 +238,7 @@ type Password struct {
// (cough cough, kubernetes), must map this value appropriately.
// (cough cough, kubernetes), must map this value appropriately.
Email
string
`yaml:"email"`
Email
string
`yaml:"email"`
// Bcrypt encoded hash of the password. This package recommends a cost value of at
// Bcrypt encoded hash of the password. This package enforces a min cost value of 10
// least 14.
Hash
[]
byte
`yaml:"hash"`
Hash
[]
byte
`yaml:"hash"`
// Optional username to display. NOT used during login.
// Optional username to display. NOT used during login.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment