Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

import flask_login 

from flask_login import login_required, current_user, logout_user 

from flask import flash 

from wtforms import ( 

    Form, PasswordField, StringField) 

from wtforms.validators import InputRequired 

 

from ldap3 import Server, Connection, Tls, LEVEL 

import ssl 

 

from flask import url_for, redirect 

 

from airflow import settings 

from airflow import models 

from airflow import configuration 

 

DEFAULT_USERNAME = 'airflow' 

 

login_manager = flask_login.LoginManager() 

login_manager.login_view = 'airflow.login'  # Calls login() bellow 

login_manager.login_message = None 

 

 

class AuthenticationError(Exception): 

    pass 

 

 

def get_ldap_connection(dn=None, password=None): 

    tls_configuration = None 

    use_ssl = False 

    try: 

        cacert = configuration.get("ldap", "cacert") 

        tls_configuration = Tls(validate=ssl.CERT_REQUIRED, ca_certs_file=cacert) 

        use_ssl = True 

    except: 

        pass 

 

    server = Server(configuration.get("ldap", "uri"), use_ssl, tls_configuration) 

    conn = Connection(server, dn, password) 

 

    if not conn.bind(): 

        raise AuthenticationError("Username or password incorrect") 

 

    return conn 

 

 

class LdapUser(models.User): 

    def __init__(self, user): 

        self.user = user 

 

    @staticmethod 

    def try_login(username, password): 

        conn = get_ldap_connection(configuration.get("ldap", "bind_user"), configuration.get("ldap", "bind_password")) 

 

        search_filter = "(&({0})({1}={2}))".format( 

            configuration.get("ldap", "user_filter"), 

            configuration.get("ldap", "user_name_attr"), 

            username 

        ) 

 

        # todo: BASE or ONELEVEL? 

 

        res = conn.search(configuration.get("ldap", "basedn"), search_filter, search_scope=LEVEL) 

 

        # todo: use list or result? 

        if not res: 

            raise AuthenticationError("Invalid username or password") 

 

        entry = conn.response[0] 

 

        conn.unbind() 

        conn = get_ldap_connection(entry['dn'], password) 

 

        if not conn: 

            raise AuthenticationError("Invalid username or password") 

 

    def is_active(self): 

        '''Required by flask_login''' 

        return True 

 

    def is_authenticated(self): 

        '''Required by flask_login''' 

        return True 

 

    def is_anonymous(self): 

        '''Required by flask_login''' 

        return False 

 

    def data_profiling(self): 

        '''Provides access to data profiling tools''' 

        return True 

 

    def is_superuser(self): 

        '''Access all the things''' 

        return True 

 

 

@login_manager.user_loader 

def load_user(userid): 

    session = settings.Session() 

    user = session.query(models.User).filter(models.User.id == userid).first() 

    session.expunge_all() 

    session.commit() 

    session.close() 

    return LdapUser(user) 

 

 

def login(self, request): 

    if current_user.is_authenticated(): 

        flash("You are already logged in") 

        return redirect(url_for('admin.index')) 

 

    username = None 

    password = None 

 

    form = LoginForm(request.form) 

 

    if request.method == 'POST' and form.validate(): 

        username = request.form.get("username") 

        password = request.form.get("password") 

 

    if not username or not password: 

        return self.render('airflow/login.html', 

                           title="Airflow - Login", 

                           form=form) 

 

    try: 

        LdapUser.try_login(username, password) 

 

        session = settings.Session() 

        user = session.query(models.User).filter( 

            models.User.username == DEFAULT_USERNAME).first() 

 

        if not user: 

            user = models.User( 

                username=DEFAULT_USERNAME, 

                is_superuser=True) 

 

        session.merge(user) 

        session.commit() 

        flask_login.login_user(LdapUser(user)) 

        session.commit() 

        session.close() 

 

        return redirect(request.args.get("next") or url_for("admin.index")) 

    except AuthenticationError: 

        flash("Incorrect login details") 

        return self.render('airflow/login.html', 

                           title="Airflow - Login", 

                           form=form) 

 

 

class LoginForm(Form): 

    username = StringField('Username', [InputRequired()]) 

    password = PasswordField('Password', [InputRequired()])