func getCredentials(a httpRequestArgs, hdrCreds *url.Userinfo, auths []string) (datastore.Credentials, errors.Error) { var creds datastore.Credentials if hdrCreds != nil { // Credentials are in the request URL: username := hdrCreds.Username() password, _ := hdrCreds.Password() creds = make(datastore.Credentials) creds[username] = password return creds, nil } if len(auths) > 0 { // Credentials are in the request header: // TODO: implement non-Basic auth (digest, ntlm) auth := auths[0] if strings.HasPrefix(auth, "Basic ") { encoded_creds := strings.Split(auth, " ")[1] decoded_creds, err := base64.StdEncoding.DecodeString(encoded_creds) if err != nil { return creds, errors.NewServiceErrorBadValue(err, CREDS) } // Authorization header is in format "user:pass" // per http://tools.ietf.org/html/rfc1945#section-10.2 u_details := strings.Split(string(decoded_creds), ":") switch len(u_details) { case 2: creds = make(datastore.Credentials) creds[u_details[0]] = u_details[1] case 3: creds = make(datastore.Credentials) // Support usernames like "local:xxx" or "admin:xxx" creds[strings.Join(u_details[:2], ":")] = u_details[2] default: // Authorization header format is incorrect return creds, errors.NewServiceErrorBadValue(nil, CREDS) } } return creds, nil } // Credentials may be in request arguments: cred_data, err := a.getCredentials() if err == nil && len(cred_data) > 0 { creds = make(datastore.Credentials) for _, cred := range cred_data { user, user_ok := cred["user"] pass, pass_ok := cred["pass"] if user_ok && pass_ok { creds[user] = pass } else { err = errors.NewServiceErrorMissingValue("user or pass") break } } } return creds, err }
// A named argument is an argument of the form: $<identifier>=json_value func (this *urlArgs) getNamedArgs() (map[string]value.Value, errors.Error) { var args map[string]value.Value for name, _ := range this.req.Form { if !strings.HasPrefix(name, "$") { continue } arg, err := this.formValue(name) if err != nil { return args, err } if len(arg) == 0 { //This is an error - there _has_ to be a value for a named argument return args, errors.NewServiceErrorMissingValue(fmt.Sprintf("named argument %s", name)) } args = addNamedArg(args, name, value.NewValue([]byte(arg))) } return args, nil }
func getScanConfiguration(a httpRequestArgs) (*scanConfigImpl, errors.Error) { var sc scanConfigImpl scan_consistency_field, err := a.getString(SCAN_CONSISTENCY, "NOT_BOUNDED") if err == nil { sc.scan_level = newScanConsistency(scan_consistency_field) if sc.scan_level == server.UNDEFINED_CONSISTENCY { err = errors.NewServiceErrorUnrecognizedValue(SCAN_CONSISTENCY, scan_consistency_field) } } if err == nil { sc.scan_wait, err = a.getDuration(SCAN_WAIT) } if err == nil { sc.scan_vector, err = a.getScanVector() } if err == nil && sc.scan_level == server.AT_PLUS && sc.scan_vector == nil { err = errors.NewServiceErrorMissingValue(SCAN_VECTOR) } return &sc, err }
func newHttpRequest(resp http.ResponseWriter, req *http.Request, bp BufferPool) *httpRequest { var httpArgs httpRequestArgs var err errors.Error e := req.ParseForm() if e != nil { err = errors.NewServiceErrorBadValue(e, "request form") } if err != nil && req.Method != "GET" && req.Method != "POST" { err = errors.NewServiceErrorHTTPMethod(req.Method) } if err == nil { httpArgs, err = getRequestParams(req) } var statement string if err == nil { statement, err = httpArgs.getStatement() } var prepared *plan.Prepared if err == nil { prepared, err = getPrepared(httpArgs) } if err == nil && statement == "" && prepared == nil { err = errors.NewServiceErrorMissingValue("statement or prepared") } var namedArgs map[string]value.Value if err == nil { namedArgs, err = httpArgs.getNamedArgs() } var positionalArgs value.Values if err == nil { positionalArgs, err = httpArgs.getPositionalArgs() } var namespace string if err == nil { namespace, err = httpArgs.getString(NAMESPACE, "") } var timeout time.Duration if err == nil { timeout, err = httpArgs.getDuration(TIMEOUT) } var readonly value.Tristate if err == nil { readonly, err = httpArgs.getTristate(READONLY) } if err == nil && readonly == value.FALSE && req.Method == "GET" { err = errors.NewServiceErrorReadonly( fmt.Sprintf("%s=false cannot be used with HTTP GET method.", READONLY)) } var metrics value.Tristate if err == nil { metrics, err = httpArgs.getTristate(METRICS) } var format Format if err == nil { format, err = getFormat(httpArgs) } if err == nil && format != JSON { err = errors.NewServiceErrorNotImplemented("format", format.String()) } var signature value.Tristate if err == nil { signature, err = httpArgs.getTristate(SIGNATURE) } var compression Compression if err == nil { compression, err = getCompression(httpArgs) } if err == nil && compression != NONE { err = errors.NewServiceErrorNotImplemented("compression", compression.String()) } var encoding Encoding if err == nil { encoding, err = getEncoding(httpArgs) } if err == nil && encoding != UTF8 { err = errors.NewServiceErrorNotImplemented("encoding", encoding.String()) } var pretty value.Tristate if err == nil { pretty, err = httpArgs.getTristate(PRETTY) } if err == nil && pretty == value.FALSE { err = errors.NewServiceErrorNotImplemented("pretty", "false") } var consistency *scanConfigImpl if err == nil { consistency, err = getScanConfiguration(httpArgs) } var creds datastore.Credentials if err == nil { creds, err = getCredentials(httpArgs, req.URL.User, req.Header["Authorization"]) } client_id := "" if err == nil { client_id, err = httpArgs.getString(CLIENT_CONTEXT_ID, "") } base := server.NewBaseRequest(statement, prepared, namedArgs, positionalArgs, namespace, readonly, metrics, signature, consistency, client_id, creds) rv := &httpRequest{ BaseRequest: *base, resp: resp, req: req, } rv.SetTimeout(rv, timeout) rv.writer = NewBufferedWriter(rv, bp) // Limit body size in case of denial-of-service attack req.Body = http.MaxBytesReader(resp, req.Body, MAX_REQUEST_BYTES) // Abort if client closes connection closeNotify := resp.(http.CloseNotifier).CloseNotify() go func() { <-closeNotify rv.Stop(server.TIMEOUT) }() if err != nil { rv.Fail(err) } return rv }