Disallow LDAP bind if trap is set; support setting trap from user form
This commit is contained in:
		
							parent
							
								
									64356d42d0
								
							
						
					
					
						commit
						decb83bdbb
					
				@ -2,7 +2,4 @@
 | 
			
		||||
- Forgot password handling
 | 
			
		||||
    - Admin password reset mechanism -> flag users as needing PW resets
 | 
			
		||||
- OAuth2 -> support refresh tokens
 | 
			
		||||
- Traps
 | 
			
		||||
    - Allow setting user trap from web UI
 | 
			
		||||
    - Don't allow external logins if trap is set
 | 
			
		||||
- Trust token page -> force username of current user
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								app/assets/app/resource/auth/Trap.resource.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								app/assets/app/resource/auth/Trap.resource.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
import CRUDBase from '../CRUDBase.js'
 | 
			
		||||
 | 
			
		||||
class TrapResource extends CRUDBase {
 | 
			
		||||
    endpoint = '/api/v1/auth/traps'
 | 
			
		||||
    required_fields = ['name', 'trap', 'redirect_to']
 | 
			
		||||
    permission_base = 'v1:auth:traps'
 | 
			
		||||
 | 
			
		||||
    item = 'Trap'
 | 
			
		||||
    plural = 'Traps'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const auth_trap = new TrapResource()
 | 
			
		||||
export { auth_trap }
 | 
			
		||||
@ -99,6 +99,16 @@ class UserResource extends CRUDBase {
 | 
			
		||||
                placeholder: 'Password',
 | 
			
		||||
                required: ['insert'],
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                name: 'Trap',
 | 
			
		||||
                field: 'trap',
 | 
			
		||||
                type: 'select.dynamic',
 | 
			
		||||
                options: {
 | 
			
		||||
                    resource: 'auth/Trap',
 | 
			
		||||
                    display: 'name',
 | 
			
		||||
                    value: 'trap',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
        ],
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,24 @@ class AuthController extends Controller {
 | 
			
		||||
        return [...super.services, 'models', 'auth', 'MFA', 'output', 'configs', 'utility']
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async get_traps(req, res, next) {
 | 
			
		||||
        const trap_config = this.configs.get('traps')
 | 
			
		||||
        const data = [{ name: '(None)', trap: '', redirect_to: '/' }]
 | 
			
		||||
        for ( const name in trap_config.types ) {
 | 
			
		||||
            if ( !trap_config.types.hasOwnProperty(name) ) continue
 | 
			
		||||
            data.push({
 | 
			
		||||
                name: name.replace(/_/g, ' ')
 | 
			
		||||
                    .split(' ')
 | 
			
		||||
                    .map(x => x.charAt(0).toUpperCase() + x.substr(1))
 | 
			
		||||
                    .join(' '),
 | 
			
		||||
                trap: name,
 | 
			
		||||
                redirect_to: trap_config.types[name].redirect_to
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return res.api(data)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async registration(req, res, next) {
 | 
			
		||||
        const User = this.models.get('auth:User')
 | 
			
		||||
        const required_fields = ['first_name', 'last_name', 'uid', 'email']
 | 
			
		||||
@ -230,6 +248,15 @@ class AuthController extends Controller {
 | 
			
		||||
        if ( req.body.tagline )
 | 
			
		||||
            user.tagline = req.body.tagline
 | 
			
		||||
 | 
			
		||||
        if ( req.body.trap ) {
 | 
			
		||||
            if ( !req.trap.trap_exists(req.body.trap) )
 | 
			
		||||
                return res.status(400)
 | 
			
		||||
                    .message('Invalid trap type.')
 | 
			
		||||
                    .api()
 | 
			
		||||
 | 
			
		||||
            user.trap = req.body.trap
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await user.reset_password(req.body.password, 'create')
 | 
			
		||||
        await user.save()
 | 
			
		||||
        return res.api(await user.to_api())
 | 
			
		||||
@ -340,6 +367,16 @@ class AuthController extends Controller {
 | 
			
		||||
        else
 | 
			
		||||
            user.tagline = ''
 | 
			
		||||
 | 
			
		||||
        if ( req.body.trap ) {
 | 
			
		||||
            if ( !req.trap.trap_exists(req.body.trap) )
 | 
			
		||||
                return res.status(400)
 | 
			
		||||
                    .message('Invalid trap type.')
 | 
			
		||||
                    .api()
 | 
			
		||||
 | 
			
		||||
            user.trap = req.body.trap
 | 
			
		||||
        } else
 | 
			
		||||
            user.trap = ''
 | 
			
		||||
 | 
			
		||||
        await user.save()
 | 
			
		||||
        return res.api()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -90,6 +90,11 @@ class LDAPController extends Injectable {
 | 
			
		||||
            return next(new LDAP.InvalidCredentialsError())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check if the resource has a trap. If so, deny access.
 | 
			
		||||
        if ( item.trap ) {
 | 
			
		||||
            return next(new LDAP.InvalidCredentialsError('This resource currently has a login trap set. Please visit the web UI to release.'))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.output.info(`Successfully bound resource as DN: ${req.dn.format(this.configs.get('ldap:server.format'))}.`)
 | 
			
		||||
        res.end()
 | 
			
		||||
        return next()
 | 
			
		||||
 | 
			
		||||
@ -77,6 +77,7 @@ class User extends AuthUser {
 | 
			
		||||
            last_name: this.last_name,
 | 
			
		||||
            email: this.email,
 | 
			
		||||
            tagline: this.tagline,
 | 
			
		||||
            trap: this.trap,
 | 
			
		||||
            group_ids: (await this.groups()).map(x => x.id),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -10,8 +10,8 @@
 | 
			
		||||
 */
 | 
			
		||||
const Middleware = [
 | 
			
		||||
    "auth:Utility",
 | 
			
		||||
    "Traps",
 | 
			
		||||
    "auth:TrustTokenUtility",
 | 
			
		||||
    "Traps",
 | 
			
		||||
    "SAMLUtility",
 | 
			
		||||
 | 
			
		||||
    // 'MiddlewareName',
 | 
			
		||||
 | 
			
		||||
@ -48,6 +48,10 @@ class TrapUtility {
 | 
			
		||||
        else if ( this.user ) return this.user.trap
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    trap_exists(name) {
 | 
			
		||||
        return !!this.configs[name]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    config() {
 | 
			
		||||
        return this.configs[this.get_trap()]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,12 @@ const auth_routes = {
 | 
			
		||||
    get: {
 | 
			
		||||
        '/mfa/enable/date': ['middleware::auth:UserOnly', 'controller::api:v1:Auth.get_mfa_enable_date'],
 | 
			
		||||
 | 
			
		||||
        '/traps': [
 | 
			
		||||
            'middleware::auth:APIRoute',
 | 
			
		||||
            ['middleware::api:Permission', { check: 'v1:auth:traps:list'}],
 | 
			
		||||
            'controller::api:v1:Auth.get_traps',
 | 
			
		||||
        ],
 | 
			
		||||
 | 
			
		||||
        '/roles': [
 | 
			
		||||
            'middleware::auth:APIRoute',
 | 
			
		||||
            ['middleware::api:Permission', { check: 'v1:auth:roles:list' }],
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user