Skip to content

Commit fe99365

Browse files
shirmoranShir Moransebrandon1
authored
Authentication (#33)
* removed JSON file creation, showing only JSON blob * updated makefile * changed DB_CONN_STR to env variable * Add ENV vars for checkmake (#15) * Added auth for using the collector * linting changes * using password salting * modifeid send-to-collector.sh * modified send-to-collector * Changed password type in index.html --------- Co-authored-by: Shir Moran <[email protected]> Co-authored-by: Brandon Palm <[email protected]>
1 parent 0fd4bd3 commit fe99365

14 files changed

+243
-49
lines changed

README.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ Cleanup after:
2828

2929
From collector's repo root directory, use the following command:
3030

31-
`./send-to-collector.sh "path/to/claim.json" "enter_executed_by" "enter_partner_name"`
31+
`./send-to-collector.sh "path/to/claim.json" "enter_executed_by" "enter_partner_name(optional)" "enter_password(optinal)`
32+
33+
# Instructions for running get-from-collector.sh
34+
35+
From collector's repo root directory, use the following command:
36+
37+
`./get-from-collector.sh "enter_partner_name" "enter_password"`
3238

3339

actions/authenticator.go

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package actions
2+
3+
import (
4+
"database/sql"
5+
"fmt"
6+
"net/http"
7+
8+
"golang.org/x/crypto/bcrypt"
9+
)
10+
11+
func authenticatePostRequest(r *http.Request, tx *sql.Tx) (string, error) {
12+
partnerName := r.FormValue(PartnerNameInputName)
13+
decodedPassword := r.FormValue(DedcodedPasswordInputName)
14+
15+
// If partner name or password are empty, make partner anonymous
16+
if partnerName == "" || decodedPassword == "" {
17+
return "", nil
18+
}
19+
20+
// Search for partner in authenticator talbe
21+
var encodedPassword string
22+
searchPartnerErr := tx.QueryRow(ExtractPartnerAndPasswordCmd, partnerName).Scan(&encodedPassword)
23+
// Encode given decoded password
24+
encodedDecodedPassword, err := bcrypt.GenerateFromPassword([]byte(decodedPassword), bcrypt.MinCost)
25+
26+
// If partner name is not recorded, add partner with encoded password
27+
if searchPartnerErr == sql.ErrNoRows {
28+
_, txErr := tx.Exec(InsertPartnerToAuthSQLCmd, partnerName, encodedDecodedPassword)
29+
if txErr != nil {
30+
handleTransactionRollback(tx, AuthError, err)
31+
return "", txErr
32+
}
33+
return partnerName, nil
34+
}
35+
if err != nil {
36+
handleTransactionRollback(tx, AuthError, err)
37+
return "", err
38+
}
39+
40+
// If partner is recorded and password is wrong throw data
41+
err = bcrypt.CompareHashAndPassword([]byte(encodedPassword), []byte(decodedPassword))
42+
if err != nil {
43+
return "", fmt.Errorf(InvalidPasswordErr)
44+
}
45+
return partnerName, nil
46+
}
47+
48+
func authenticateGetRequest(r *http.Request, db *sql.DB) (string, error) {
49+
partnerName := r.FormValue(PartnerNameInputName)
50+
decodedPassword := r.FormValue(DedcodedPasswordInputName)
51+
52+
// Search for partner in authenticator talbe
53+
var encodedPassword string
54+
err := db.QueryRow(ExtractPartnerAndPasswordCmd, partnerName).Scan(&encodedPassword)
55+
if err != nil {
56+
return "", err
57+
}
58+
59+
// Compare encoded and given passwords
60+
err = bcrypt.CompareHashAndPassword([]byte(encodedPassword), []byte(decodedPassword))
61+
if err != nil {
62+
return "", fmt.Errorf(InvalidPasswordErr)
63+
}
64+
65+
return partnerName, nil
66+
}

actions/constants.go

+21-11
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,25 @@ const FormFileErr = "Error found while forming file: %s"
88
const ReadingFileErr = "Error found while reading claim file: %s"
99
const UnmarshalErr = "Error found while trying to unmarshal claim file: %s"
1010
const MarshalErr = "Error found while marshaling claim file: %s"
11-
const MalformedClaimFileErr = "Malformed claim file: "
12-
const ClaimFieldMissingErr = MalformedClaimFileErr + "claim field is missing."
13-
const VersionsFieldMissingErr = MalformedClaimFileErr + "versions field is missing."
14-
const OcpFieldMissingErr = MalformedClaimFileErr + "ocp subfield of versions field is missing."
15-
const TestMissingErr = MalformedClaimFileErr + "%s subfield of results field is missing."
16-
const TestTestIDMissingErr = MalformedClaimFileErr + "testID subfield of %s test is missing."
17-
const TestStateMissingErr = MalformedClaimFileErr + "state subfield of %s test is missing."
18-
const TestIDSuiteMissingErr = MalformedClaimFileErr + "suite subfield of %s's testID field is missing."
19-
const TestIDIDMissingErr = MalformedClaimFileErr + "id subfield of %s's testID field is missing."
20-
const ResultsFieldMissingErr = MalformedClaimFileErr + "results field is missing."
21-
const ExecutedByMissingErr = MalformedClaimFileErr + "executed by value is missing."
11+
const MalformedClaimFileErr = "Malformed claim file: %s"
12+
const ClaimFieldMissingErr = "claim field is missing."
13+
const VersionsFieldMissingErr = "versions field is missing."
14+
const OcpFieldMissingErr = "ocp subfield of versions field is missing."
15+
const TestTestIDMissingErr = "testID subfield of %s test is missing."
16+
const TestStateMissingErr = "state subfield of %s test is missing."
17+
const TestIDSuiteMissingErr = "suite subfield of %s's testID field is missing."
18+
const TestIDIDMissingErr = "id subfield of %s's testID field is missing."
19+
const ResultsFieldMissingErr = "results field is missing."
20+
const ExecutedByMissingErr = "Executed by value is missing."
2221
const MalformedJSONFileErr = "Malformed json file."
22+
const InvalidPasswordErr = "invalid password to given partner's name"
2323
const RollbackErr = "Error found while Rollbacking transaction: %s"
2424
const ExecQueryErr = "Error found while executing a mysql query: %s"
2525
const ScanDBFieldErr = "Error found while scanning db field: %s"
2626
const BeginTxErr = "Error found while beginning transaction: %s"
2727
const CommitTxErr = "Error found while committing transaction: %s"
28+
const AuthError = "Error found while authenticating partner's password: %s"
29+
const EncodingPasswordError = "Failed encoding password." // #nosec
2830

2931
// parser.go constants
3032
const ClaimTag = "claim"
@@ -33,6 +35,7 @@ const ResultsTag = "results"
3335
const ClaimFileInputName = "claimFile"
3436
const ExecutedByInputName = "executed_by"
3537
const PartnerNameInputName = "partner_name"
38+
const DedcodedPasswordInputName = "decoded_password"
3639

3740
const UseCollectorSQLCmd = `USE cnf; `
3841
const InsertToClaimSQLCmd = `INSERT INTO claim
@@ -42,11 +45,18 @@ const InsertToClaimResSQLCmd = `INSERT INTO claim_result
4245
(claim_id, suite_name, test_id, test_status)
4346
VALUES (?, ?, ?, ?);`
4447
const ExtractLastClaimID = `SELECT id FROM cnf.claim ORDER BY id DESC LIMIT 1;`
48+
const ExtractPartnerAndPasswordCmd = `SELECT encoded_password FROM cnf.authenticator WHERE partner_name = ?`
49+
const InsertPartnerToAuthSQLCmd = `INSERT INTO cnf.authenticator (partner_name, encoded_password) VALUES (?, ?)`
4550
const ParseLowerBound = 10
4651
const ParseUpperBound = 20
4752

4853
const SuccessUploadingFileMSG = "File was uploaded successfully!"
4954

5055
// results.go constants
56+
const SelectAllFromClaimByPartner = "SELECT * FROM cnf.claim WHERE partner_name = ?"
5157
const SelectAllFromClaim = "SELECT * FROM cnf.claim"
58+
const SelectAllClaimIDsByPartner = "SELECT id FROM cnf.claim WHERE partner_name = ?"
59+
const SelectAllFromClaimResultByClaimIDs = "SELECT * FROM cnf.claim_result WHERE claim_id IN (%s)"
5260
const SelectAllFromClaimResult = "SELECT * FROM cnf.claim_result"
61+
const InvalidUserOrPasswordErr = "Invalid user name or password." // #nosec
62+
const AdminUserName = "admin"

actions/parser.go

+43-30
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,39 @@ import (
1212
"github.com/sirupsen/logrus"
1313
)
1414

15-
func handleTransactionRollback(tx *sql.Tx, err error, context string) {
15+
func handleTransactionRollback(tx *sql.Tx, context string, err error) {
1616
txErr := tx.Rollback()
1717
if txErr != nil {
1818
logrus.Errorf(RollbackErr, txErr)
1919
}
2020
logrus.Errorf(context, err)
2121
}
2222

23-
func writeResponse(w http.ResponseWriter, context, response string) {
24-
_, writeErr := w.Write([]byte(response + "\n"))
23+
func writeError(w http.ResponseWriter, context, err string) {
24+
_, writeErr := w.Write([]byte(err + "\n"))
2525
if writeErr != nil {
2626
logrus.Errorf(WritingResponseErr, writeErr)
2727
}
28-
logrus.Errorf(context, response)
28+
logrus.Errorf(context, err)
2929
}
3030

3131
func readClaimFile(w http.ResponseWriter, r *http.Request) []byte {
3232
err := r.ParseMultipartForm(ParseLowerBound << ParseUpperBound)
3333
if err != nil {
34-
writeResponse(w, RequestContentTypeErr, err.Error())
34+
writeError(w, RequestContentTypeErr, err.Error())
3535
return nil
3636
}
3737

3838
claimFile, _, err := r.FormFile(ClaimFileInputName)
3939
if err != nil {
40-
writeResponse(w, FormFileErr, err.Error())
40+
writeError(w, FormFileErr, err.Error())
4141
return nil
4242
}
4343
defer claimFile.Close()
4444

4545
claimFileBytes, err := io.ReadAll(claimFile)
4646
if err != nil {
47-
writeResponse(w, ReadingFileErr, err.Error())
47+
writeError(w, ReadingFileErr, err.Error())
4848
return nil
4949
}
5050

@@ -61,13 +61,13 @@ func uploadAndConvertClaimFile(w http.ResponseWriter, r *http.Request) map[strin
6161
var claimFileMap map[string]interface{}
6262
err := json.Unmarshal(claimFileBytes, &claimFileMap)
6363
if err != nil {
64-
writeResponse(w, UnmarshalErr, err.Error())
64+
writeError(w, UnmarshalErr, err.Error())
6565
return nil
6666
}
6767

6868
_, keyExists := claimFileMap[ClaimTag]
6969
if !keyExists {
70-
writeResponse(w, "%s", ClaimFieldMissingErr)
70+
writeError(w, MalformedClaimFileErr, ClaimFieldMissingErr)
7171
return nil
7272
}
7373
return claimFileMap[ClaimTag].(map[string]interface{})
@@ -76,37 +76,36 @@ func uploadAndConvertClaimFile(w http.ResponseWriter, r *http.Request) map[strin
7676
func validateClaimKeys(w http.ResponseWriter, claimFileMap map[string]interface{}) map[string]interface{} {
7777
versions, keyExists := claimFileMap[VersionsTag].(map[string]interface{})
7878
if !keyExists {
79-
writeResponse(w, "%s", VersionsFieldMissingErr)
79+
writeError(w, MalformedClaimFileErr, VersionsFieldMissingErr)
8080
return nil
8181
}
8282

8383
_, keyExists = versions["ocp"]
8484
if !keyExists {
85-
writeResponse(w, "%s", OcpFieldMissingErr)
85+
writeError(w, MalformedClaimFileErr, OcpFieldMissingErr)
8686
return nil
8787
}
8888

8989
return versions
9090
}
9191

92-
func insertToClaimTable(w http.ResponseWriter, r *http.Request, tx *sql.Tx, claimFileMap map[string]interface{}) bool {
92+
func insertToClaimTable(w http.ResponseWriter, r *http.Request, tx *sql.Tx, claimFileMap map[string]interface{}, partnerName string) bool {
9393
versions := validateClaimKeys(w, claimFileMap)
9494
if versions == nil {
9595
return false
9696
}
9797

9898
// saving users input referring to who executed claim file and partner's name
9999
executedBy := r.FormValue(ExecutedByInputName)
100-
partnerName := r.FormValue(PartnerNameInputName)
101100

102101
if executedBy == "" {
103-
writeResponse(w, "%s", ExecutedByMissingErr)
102+
writeError(w, "%s", ExecutedByMissingErr)
104103
return false
105104
}
106105

107106
_, err := tx.Exec(InsertToClaimSQLCmd, versions["ocp"].(string), executedBy, time.Now(), partnerName)
108107
if err != nil {
109-
handleTransactionRollback(tx, err, ExecQueryErr)
108+
handleTransactionRollback(tx, ExecQueryErr, err)
110109
return false
111110
}
112111
return true
@@ -141,69 +140,83 @@ func validateInnerResultsKeys(results map[string]interface{}, testName string) (
141140
func insertToClaimResultTable(w http.ResponseWriter, tx *sql.Tx, claimFileMap map[string]interface{}) bool {
142141
results, keyExists := claimFileMap[ResultsTag].(map[string]interface{})
143142
if !keyExists {
144-
writeResponse(w, "%s", ResultsFieldMissingErr)
143+
writeError(w, MalformedClaimFileErr, ResultsFieldMissingErr)
145144
return false
146145
}
147146

148147
var claimID string
149148
err := tx.QueryRow(ExtractLastClaimID).Scan(&claimID)
150149
if err != nil {
151-
handleTransactionRollback(tx, err, ScanDBFieldErr)
150+
handleTransactionRollback(tx, ScanDBFieldErr, err)
152151
return false
153152
}
154153

155154
for testName := range results {
156155
testData, testID, keyErr := validateInnerResultsKeys(results, testName)
157156
if keyErr != "" {
158-
writeResponse(w, "%s", keyErr)
157+
writeError(w, MalformedClaimFileErr, keyErr)
159158
return false
160159
}
161160
_, err = tx.Exec(InsertToClaimResSQLCmd, claimID, testID["suite"].(string),
162161
testID["id"].(string), testData["state"].(string))
163162
if err != nil {
164-
handleTransactionRollback(tx, err, ExecQueryErr)
163+
handleTransactionRollback(tx, ExecQueryErr, err)
165164
return false
166165
}
167166
}
168167
return true
169168
}
170169

171-
func parseClaimFile(w http.ResponseWriter, r *http.Request, tx *sql.Tx, claimFileMap map[string]interface{}) bool {
170+
func parseClaimFile(w http.ResponseWriter, r *http.Request, tx *sql.Tx, claimFileMap map[string]interface{}, partnerName string) bool {
172171
_, err := tx.Exec(UseCollectorSQLCmd)
173172
if err != nil {
174-
handleTransactionRollback(tx, err, ExecQueryErr)
173+
handleTransactionRollback(tx, ExecQueryErr, err)
175174
return false
176175
}
177176

178-
if insertToClaimTable(w, r, tx, claimFileMap) && insertToClaimResultTable(w, tx, claimFileMap) {
177+
if insertToClaimTable(w, r, tx, claimFileMap, partnerName) && insertToClaimResultTable(w, tx, claimFileMap) {
179178
return true
180179
}
181180
return false
182181
}
183182

184183
func ParserHandler(w http.ResponseWriter, r *http.Request, db *sql.DB) {
185-
claimFileMap := uploadAndConvertClaimFile(w, r)
186-
if claimFileMap == nil {
187-
// error occurred while uploading\converting claim file.
188-
return
189-
}
190184
// Beginning the transaction.
191185
tx, err := db.Begin()
192186
if err != nil {
193187
logrus.Errorf(BeginTxErr, err)
194188
return
195189
}
196190

191+
// Authonticate partner name and password
192+
partnerName, err := authenticatePostRequest(r, tx)
193+
if err != nil {
194+
writeError(w, AuthError, err.Error())
195+
return
196+
}
197+
198+
claimFileMap := uploadAndConvertClaimFile(w, r)
199+
if claimFileMap == nil {
200+
// error occurred while uploading\converting claim file.
201+
return
202+
}
203+
197204
// Check if an error occurred while parsing (which caused a Rollback).
198-
if !parseClaimFile(w, r, tx, claimFileMap) {
205+
if !parseClaimFile(w, r, tx, claimFileMap, partnerName) {
199206
return
200207
}
201208

202209
// If no error occurred, commit the transaction to make database changes.
203210
err = tx.Commit()
204211
if err != nil {
205-
handleTransactionRollback(tx, err, CommitTxErr)
212+
handleTransactionRollback(tx, CommitTxErr, err)
206213
return
207214
}
208-
writeResponse(w, "%s", SuccessUploadingFileMSG)
215+
216+
// Succfully uploaded file
217+
_, writeErr := w.Write([]byte(SuccessUploadingFileMSG + "\n"))
218+
if writeErr != nil {
219+
logrus.Errorf(WritingResponseErr, writeErr)
220+
}
221+
logrus.Info(SuccessUploadingFileMSG)
209222
}

0 commit comments

Comments
 (0)