Beispiel #1
0
// bcryptAuthenticate uses the bcrypt authentication method to log in to the API, returning
// a session user and a pair of client/server errors
func bcryptAuthenticate(req *http.Request) (*data.User, *data.Session, error, error) {
	// Username and password for authentication
	var username string
	var password string

	// Check for empty authorization header
	if req.Header.Get("Authorization") == "" {
		// If no header, check for credentials via POST parameters
		username = req.PostFormValue("username")
		password = req.PostFormValue("password")
	} else {
		// Fetch credentials from HTTP Basic auth
		tempUsername, tempPassword, err := basicCredentials(req.Header.Get("Authorization"))
		if err != nil {
			return nil, nil, err, nil
		}

		// Copy credentials
		username = tempUsername
		password = tempPassword
	}

	// Check if either credential is blank
	if username == "" {
		return nil, nil, ErrNoUsername, nil
	} else if password == "" {
		return nil, nil, ErrNoPassword, nil
	}

	// Attempt to load user by username
	user := new(data.User)
	user.Username = username
	if err := user.Load(); err != nil {
		// Check for invalid user
		if err == sql.ErrNoRows {
			return nil, nil, ErrInvalidUsername, nil
		}

		// Server error
		return nil, nil, nil, err
	}

	// Compare input password with bcrypt password, checking for errors
	err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
	if err != nil && err == bcrypt.ErrMismatchedHashAndPassword {
		// Mismatch password
		return nil, nil, ErrInvalidPassword, nil
	} else if err != nil && err != bcrypt.ErrMismatchedHashAndPassword {
		// Return server error
		return nil, nil, nil, err
	}

	// No errors, return session user, but no session because one does not exist yet
	return user, nil, nil, nil
}
Beispiel #2
0
// simpleAuthenticate uses the simple authentication method to log in to the API, returning
// a session user and a pair of client/server errors.
func simpleAuthenticate(req *http.Request) (*data.User, *data.Session, error, error) {
	// Verify that SimpleAuth was triggered in debug mode
	if !env.IsDebug() {
		return nil, nil, nil, errors.New("not in debug mode")
	}

	// Username for authentication
	var username string

	// Check for empty authorization header
	if req.Header.Get("Authorization") == "" {
		// If no header, check for credentials via querystring parameters
		query := req.URL.Query()
		username = query.Get("u")
	} else {
		// Fetch credentials from HTTP Basic auth
		tempUsername, _, err := basicCredentials(req.Header.Get("Authorization"))
		if err != nil {
			return nil, nil, err, nil
		}

		// Copy credentials
		username = tempUsername
	}

	// Check if username is blank
	if username == "" {
		return nil, nil, ErrNoUsername, nil
	}

	// Attempt to load user by username
	user := new(data.User)
	user.Username = username
	if err := user.Load(); err != nil {
		// Check for invalid user
		if err == sql.ErrNoRows {
			return nil, nil, errors.New("invalid username"), nil
		}

		// Server error
		return nil, nil, nil, err
	}

	// No errors, return session user, but no session because one does not exist yet
	return user, nil, nil, nil
}
Beispiel #3
0
// subsonicAuthenticate uses the Subsonic authentication method to log in to the API, returning
// only a pair of client/server errors
func subsonicAuthenticate(req *http.Request) (*data.User, *data.Session, error, error) {
	// Check for required credentials via querystring
	query := req.URL.Query()
	username := query.Get("u")
	password := query.Get("p")

	// Check if username or password is blank
	if username == "" || password == "" {
		return nil, nil, subsonic.ErrBadCredentials, nil
	}

	// Check for Subsonic version
	version := query.Get("v")
	if version == "" {
		return nil, nil, subsonic.ErrMissingParameter, nil
	}

	// TODO: reevaluate this strategy in the future, but for now, we will use a user's wavepipe session
	// TODO: key as their Subsonic password.  This will mean that the username and session key are passed on
	// TODO: every request, but also means that no more database schema must be added for Subsonic authentication.

	// Check for "enc:" prefix, specifying a hex-encoded password
	if strings.HasPrefix(password, "enc:") {
		// Decode hex string
		out, err := hex.DecodeString(password[4:])
		if err != nil {
			return nil, nil, nil, err
		}

		password = string(out)
	}

	// Attempt to load session by key passed via Subsonic password parameter
	session := new(data.Session)
	session.Key = password
	if err := session.Load(); err != nil {
		// Check for invalid user
		if err == sql.ErrNoRows {
			return nil, nil, subsonic.ErrBadCredentials, nil
		}

		// Server error
		return nil, nil, nil, err
	}

	// Attempt to load associated user by username from Subsonic username parameter
	user := new(data.User)
	user.Username = username
	if err := user.Load(); err != nil {
		// Server error
		return nil, nil, nil, err
	}

	// Update session expiration date by 1 week
	session.Expire = time.Now().Add(7 * 24 * time.Hour).Unix()
	if err := session.Update(); err != nil {
		return nil, nil, nil, err
	}

	// No errors, return no user or session because the emulated Subsonic API is read-only
	return nil, nil, nil, nil
}