Login working

This commit is contained in:
Matej Kramny 2016-03-18 23:23:03 +00:00
parent 0f180756ab
commit ad860ef236
9 changed files with 117 additions and 17 deletions

View File

@ -1,28 +1,25 @@
create table user (
`id` varchar (255) not null comment "UUID v4",
`created` datetime not null default NOW() comment "Created timestamp",
`id` int(11) not null auto_increment primary key,
`created` datetime not null default NOW(),
`username` varchar(255) not null comment "Username, unique",
`name` varchar(255) not null comment "Full name",
`email` varchar(255) not null comment "Email, unique",
`password` varchar(255) not null comment "Password",
UNIQUE KEY `username` (`username`),
UNIQUE KEY `email` (`email`),
PRIMARY KEY `id` (`id`)
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB CHARSET=utf8;
create table project (
`id` varchar (255) not null comment "UUID v4",
`id` int(11) not null auto_increment primary key,
`created` datetime not null default NOW() comment "Created timestamp",
`name` varchar(255) not null comment "Project name",
PRIMARY KEY `id` (`id`)
`name` varchar(255) not null comment "Project name"
) ENGINE=InnoDB CHARSET=utf8;
create table project__user (
`project_id` varchar (255) not null comment "Project ID",
`project_id` int(11) not null,
`user_id` varchar (255) not null comment "User ID",
`admin` tinyint (1) not null default 0 comment `Gives user god-like privileges`,
`admin` tinyint (1) not null default 0 comment 'Gives user god-like privileges',
UNIQUE KEY `id` (`project_id`, `user_id`)
) ENGINE=InnoDB CHARSET=utf8;

View File

@ -7,7 +7,7 @@ import (
)
type User struct {
ID string `db:"id" json:"id"`
ID int `db:"id" json:"id"`
Created time.Time `db:"created" json:"created"`
Username string `db:"username" json:"username"`
Name string `db:"name" json:"name"`

View File

@ -6,9 +6,9 @@
span(ng-bind="status")
.form-group(style="margin-top: 25px"): .col-sm-12
input.text-center.form-control.input-lg(type="email" ng-model="user.auth" placeholder="Email / Username")
input.text-center.form-control.input-lg(type="text" ng-model="user.auth" placeholder="Email / Username")
.form-group: .col-sm-12
input.text-center.form-control.input-lg(type="password" required ng-model="user.password" placeholder="Password")
input.text-center.form-control.input-lg(type="password" ng-model="user.password" placeholder="Password")
.form-group(style="margin-top: 25px"): .col-sm-12
button.btn.btn-primary.btn-block.btn-lg(ng-click="authenticate(user)") Sign In

View File

@ -2,6 +2,22 @@ var app = angular.module('semaphore', ['scs.couch-potato', 'ui.router', 'ui.boot
couchPotato.configureApp(app);
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push(['$q', '$injector', '$log', function ($q, $injector, $log) {
return {
request: function (request) {
var url = request.url;
if (!(url.indexOf('/public') !== -1 || url.indexOf('://') !== -1)) {
request.url = "/api" + request.url;
request.headers['Cache-Control'] = 'no-cache';
}
return request || $q.when(request);
}
};
}]);
}]);
app.run(['$rootScope', '$window', '$couchPotato', '$injector', '$state', '$http', function ($rootScope, $window, $couchPotato, $injector, $state, $http) {
app.lazy = $couchPotato;
@ -30,7 +46,7 @@ app.run(['$rootScope', '$window', '$couchPotato', '$injector', '$state', '$http'
$rootScope.user = null;
$rootScope.loggedIn = false;
$http.get('/api/user')
$http.get('/user')
.then(function (user) {
$rootScope.user = user;
$rootScope.loggedIn = true;

View File

@ -12,7 +12,7 @@ define(function () {
var pwd = user.password;
user.password = "";
$http.post('/auth/password', {
$http.post('/auth/login', {
auth: user.auth,
password: pwd
}).success(function (data, status) {

View File

@ -1,6 +1,6 @@
app.config(function ($stateProvider, $urlRouterProvider, $locationProvider, $couchPotatoProvider) {
$stateProvider.state('login', {
url: '/',
url: '/login',
pageTitle: "Sign In",
templateUrl: "/public/html/auth/login.html",
controller: "SignInCtrl",

67
routes/auth/login.go Normal file
View File

@ -0,0 +1,67 @@
package auth
import (
"database/sql"
"fmt"
"net/mail"
"strings"
"time"
"golang.org/x/crypto/bcrypt"
"github.com/ansible-semaphore/semaphore/database"
"github.com/ansible-semaphore/semaphore/models"
"github.com/gin-gonic/gin"
sq "github.com/masterminds/squirrel"
)
func Login(c *gin.Context) {
var login struct {
Auth string `json:"auth" binding:"required"`
Password string `json:"password" binding:"required"`
}
if err := c.Bind(&login); err != nil {
return
}
login.Auth = strings.ToLower(login.Auth)
q := sq.Select("*").
From("user")
_, err := mail.ParseAddress(login.Auth)
if err == nil {
q = q.Where("email=?", login.Auth)
} else {
q = q.Where("username=?", login.Auth)
}
query, args, _ := q.ToSql()
fmt.Println(query, args)
var user models.User
if err := database.Mysql.SelectOne(&user, query, args...); err != nil {
if err == sql.ErrNoRows {
c.AbortWithStatus(400)
return
}
panic(err)
}
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(login.Password)); err != nil {
c.AbortWithStatus(400)
return
}
session := c.MustGet("session").(models.Session)
session.UserID = &user.ID
status := database.Redis.Set("session:"+session.ID, string(session.Encode()), 7*24*time.Hour)
if err := status.Err(); err != nil {
panic(err)
}
c.AbortWithStatus(204)
}

View File

@ -3,6 +3,7 @@ package routes
import (
"strings"
"github.com/ansible-semaphore/semaphore/routes/auth"
"github.com/ansible-semaphore/semaphore/util"
"github.com/gin-gonic/gin"
)
@ -20,7 +21,9 @@ func Route(r *gin.Engine) {
api.Use(authentication)
// serve /api/auth
func(api *gin.RouterGroup) {
api.POST("/login", auth.Login)
}(api.Group("/auth"))
api.Use(MustAuthenticate)
@ -31,6 +34,11 @@ func Route(r *gin.Engine) {
func servePublic(c *gin.Context) {
path := c.Request.URL.Path
if strings.HasPrefix(path, "/api") {
c.Next()
return
}
if !strings.HasPrefix(path, "/public") {
path = "/public/html/index.html"
}

View File

@ -6,6 +6,8 @@ import (
"fmt"
"os"
"golang.org/x/crypto/bcrypt"
"github.com/bugsnag/bugsnag-go"
"github.com/gin-gonic/gin"
"github.com/mattbaird/gochimp"
@ -45,8 +47,18 @@ func init() {
flag.BoolVar(&Migration, "migrate", false, "execute migrations")
path := flag.String("config", "", "config path")
var pwd string
flag.StringVar(&pwd, "hash", "", "generate hash of given password")
flag.Parse()
if len(pwd) > 0 {
password, _ := bcrypt.GenerateFromPassword([]byte(pwd), 11)
fmt.Println("Generated password: ", string(password))
os.Exit(0)
}
if path != nil && len(*path) > 0 {
// load
file, err := os.Open(*path)